psa-crypto-0.9.2/.cargo_vcs_info.json 0000644 00000000150 00000000001 0013141 0 ustar {
"git": {
"sha1": "833f949b367713f8e23815cdb020c718b093ce3e"
},
"path_in_vcs": "psa-crypto"
} psa-crypto-0.9.2/Cargo.toml 0000644 00000002706 00000000001 0011150 0 ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "psa-crypto"
version = "0.9.2"
authors = ["Parsec Project Contributors"]
description = "Wrapper around the PSA Cryptography API"
readme = "README.md"
keywords = [
"psa",
"crypto",
"cryptography",
"no_std",
]
categories = [
"api-bindings",
"external-ffi-bindings",
"cryptography",
]
license = "Apache-2.0"
repository = "https://github.com/parallaxsecond/rust-psa-crypto"
[dependencies.log]
version = "0.4.11"
[dependencies.psa-crypto-sys]
version = "0.9.3"
default-features = false
[dependencies.serde]
version = "1.0.115"
features = ["derive"]
[dependencies.zeroize]
version = "1.4.3"
features = ["zeroize_derive"]
[dev-dependencies.base64]
version = "0.12.3"
[dev-dependencies.rand]
version = "0.8.4"
[dev-dependencies.rsa]
version = "0.5.0"
features = ["alloc"]
[features]
default = [
"operations",
"no-std",
]
interface = ["psa-crypto-sys/interface"]
no-std = []
operations = [
"psa-crypto-sys/operations",
"interface",
]
psa-crypto-0.9.2/Cargo.toml.orig 0000644 0000000 0000000 00000001603 10461020230 0014624 0 ustar 0000000 0000000 [package]
name = "psa-crypto"
version = "0.9.2"
authors = ["Parsec Project Contributors"]
edition = "2018"
description = "Wrapper around the PSA Cryptography API"
readme = "README.md"
keywords = ["psa", "crypto", "cryptography", "no_std"]
categories = ["api-bindings", "external-ffi-bindings", "cryptography"]
license = "Apache-2.0"
repository = "https://github.com/parallaxsecond/rust-psa-crypto"
[dependencies]
psa-crypto-sys = { path = "../psa-crypto-sys", version = "0.9.3", default-features = false }
log = "0.4.11"
serde = { version = "1.0.115", features = ["derive"] }
zeroize = { version = "1.4.3", features = ["zeroize_derive"] }
[dev-dependencies]
rsa = { version = "0.5.0", features = ["alloc"] }
rand = "0.8.4"
base64 = "0.12.3"
[features]
default = ["operations", "no-std"]
operations = ["psa-crypto-sys/operations", "interface"]
interface = ["psa-crypto-sys/interface"]
no-std = []
psa-crypto-0.9.2/LICENSE 0000644 0000000 0000000 00000026136 10461020230 0012752 0 ustar 0000000 0000000
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.
psa-crypto-0.9.2/README.md 0000644 0000000 0000000 00000002442 10461020230 0013216 0 ustar 0000000 0000000 # PSA Cryptography API Rust Wrapper
This is the higher-level, more Rust-friendly interface.
## Mbed Crypto backing
The features of this crate can modify what is compiled in from the PSA Crypto
specification:
* `operations`: everything is included. The `psa-crypto-sys` crate statically
links by default Mbed Crypto. See the documentation of [that
crate](https://github.com/parallaxsecond/rust-psa-crypto/tree/main/psa-crypto-sys)
to see how to modify the linking options. This feature is activated by default.
* `interface`: only the abstraction over the PSA Crypto interface (types,
helper methods) are included. The `MBEDTLS_INCLUDE_DIR` environment variable
is needed to produce Rust shims around PSA Crypto macros.
* without any of the above: only the specification-defined parts are included.
psa-crypto-0.9.2/src/lib.rs 0000644 0000000 0000000 00000005171 10461020230 0013644 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PSA Cryptography API Wrapper
//!
//! This crate provides abstraction over an implementation of the PSA Cryptography API.
//! Please check the API
//! [here](https://developer.arm.com/architectures/security-architectures/platform-security-architecture/documentation)
//! for a more complete description of operations and types.
//! This abstraction is built on top of the `psa-crypto-sys` crate.
#![cfg_attr(feature = "no-std", no_std)]
#![deny(
nonstandard_style,
const_err,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
no_mangle_generic_items,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
private_in_public,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true,
missing_debug_implementations,
missing_docs,
// The following ling is triggered when casting a reference to a raw pointer.
//trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results,
missing_copy_implementations
)]
// This one is hard to avoid.
#![allow(clippy::multiple_crate_versions)]
#[cfg(feature = "operations")]
pub mod operations;
pub mod types;
pub use psa_crypto_sys as ffi;
#[cfg(feature = "operations")]
use core::sync::atomic::{AtomicBool, Ordering};
#[cfg(feature = "operations")]
use types::status::{Error, Result, Status};
#[cfg(feature = "operations")]
static INITIALISED: AtomicBool = AtomicBool::new(false);
/// Initialize the PSA Crypto library
///
/// Applications must call this function before calling any other function in crate.
/// Applications are permitted to call this function more than once. Once a call succeeds,
/// subsequent calls are guaranteed to succeed.
///
///
/// # Example
///
/// ```rust
/// use psa_crypto::init;
/// init().unwrap();
/// // Can be called twice
/// init().unwrap();
/// ```
#[cfg(feature = "operations")]
pub fn init() -> Result<()> {
// It is not a problem to call psa_crypto_init more than once.
Status::from(unsafe { psa_crypto_sys::psa_crypto_init() }).to_result()?;
INITIALISED.store(true, Ordering::Relaxed);
Ok(())
}
/// Check if the PSA Crypto library has been initialized
///
/// Example
///
/// ```
/// use psa_crypto::{initialized, init};
/// init().unwrap();
/// initialized().unwrap();
/// ```
#[cfg(feature = "operations")]
pub fn initialized() -> Result<()> {
if INITIALISED.load(Ordering::Relaxed) {
Ok(())
} else {
Err(Error::BadState)
}
}
psa-crypto-0.9.2/src/operations/aead.rs 0000644 0000000 0000000 00000012502 10461020230 0016147 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Authenticated Encryption with Associated Data (AEAD) operations
//!
//! See the PSA Crypto API for the format of the different parameters used in this module.
use crate::initialized;
use crate::types::algorithm::Aead;
use crate::types::key::Id;
use crate::types::status::{Result, Status};
/// Process an authenticated encryption operation.
/// # Example
///
/// ```
/// use psa_crypto::types::algorithm::{Aead, AeadWithDefaultLengthTag};
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::operations::{key_management, aead};
/// # const KEY_DATA: [u8; 16] = [0x41, 0x89, 0x35, 0x1B, 0x5C, 0xAE, 0xA3, 0x75, 0xA0, 0x29, 0x9E, 0x81, 0xC6, 0x21, 0xBF, 0x43];
/// # const NONCE: [u8; 13] = [0x48, 0xc0, 0x90, 0x69, 0x30, 0x56, 0x1e, 0x0a, 0xb0, 0xef, 0x4c, 0xd9, 0x72];
/// # const ADDITIONAL_DATA: [u8; 32] = [0x40, 0xa2, 0x7c, 0x1d, 0x1e, 0x23, 0xea, 0x3d, 0xbe, 0x80, 0x56, 0xb2,
/// # 0x77, 0x48, 0x61, 0xa4, 0xa2, 0x01, 0xcc, 0xe4, 0x9f, 0x19, 0x99, 0x7d, 0x19, 0x20, 0x6d, 0x8c, 0x8a, 0x34, 0x39, 0x51];
/// # const INPUT_DATA: [u8; 24] = [0x45, 0x35, 0xd1, 0x2b, 0x43, 0x77, 0x92, 0x8a, 0x7c, 0x0a, 0x61, 0xc9, 0xf8, 0x25, 0xa4, 0x86,
/// # 0x71, 0xea, 0x05, 0x91, 0x07, 0x48, 0xc8, 0xef];
/// let alg = Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm);
/// let mut usage_flags: UsageFlags = Default::default();
/// usage_flags.set_encrypt();
/// let attributes = Attributes {
/// key_type: Type::Aes,
/// bits: 0,
/// lifetime: Lifetime::Volatile,
/// policy: Policy {
/// usage_flags,
/// permitted_algorithms: alg.into(),
/// },
/// };
/// psa_crypto::init().unwrap();
/// let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
/// let output_buffer_size = attributes.aead_encrypt_output_size(alg.into(), INPUT_DATA.len()).unwrap();
/// let mut output_buffer = vec![0; output_buffer_size];
/// let length = aead::encrypt(my_key, alg, &NONCE, &ADDITIONAL_DATA, &INPUT_DATA, &mut output_buffer).unwrap();
/// output_buffer.resize(length, 0);
/// ```
pub fn encrypt(
key_id: Id,
aead_alg: Aead,
nonce: &[u8],
additional_data: &[u8],
plaintext: &[u8],
ciphertext: &mut [u8],
) -> Result {
initialized()?;
let mut ciphertext_size = 0;
Status::from(unsafe {
psa_crypto_sys::psa_aead_encrypt(
key_id.0,
aead_alg.into(),
nonce.as_ptr(),
nonce.len(),
additional_data.as_ptr(),
additional_data.len(),
plaintext.as_ptr(),
plaintext.len(),
ciphertext.as_mut_ptr(),
ciphertext.len(),
&mut ciphertext_size,
)
})
.to_result()?;
Ok(ciphertext_size)
}
/// Process an authenticated decryption operation.
/// # Example
///
/// ```
/// use psa_crypto::types::algorithm::{Aead, AeadWithDefaultLengthTag};
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::operations::{key_management, aead};
/// # const KEY_DATA: [u8; 16] = [0x41, 0x89, 0x35, 0x1B, 0x5C, 0xAE, 0xA3, 0x75, 0xA0, 0x29, 0x9E, 0x81, 0xC6, 0x21, 0xBF, 0x43];
/// # const NONCE: [u8; 13] = [0x48, 0xc0, 0x90, 0x69, 0x30, 0x56, 0x1e, 0x0a, 0xb0, 0xef, 0x4c, 0xd9, 0x72];
/// # const ADDITIONAL_DATA: [u8; 32] = [0x40, 0xa2, 0x7c, 0x1d, 0x1e, 0x23, 0xea, 0x3d, 0xbe, 0x80, 0x56, 0xb2,
/// # 0x77, 0x48, 0x61, 0xa4, 0xa2, 0x01, 0xcc, 0xe4, 0x9f, 0x19, 0x99, 0x7d, 0x19, 0x20, 0x6d, 0x8c, 0x8a, 0x34, 0x39, 0x51];
/// # const INPUT_DATA: [u8; 40] = [0x26, 0xc5, 0x69, 0x61, 0xc0, 0x35, 0xa7, 0xe4, 0x52, 0xcc, 0xe6, 0x1b, 0xc6, 0xee, 0x22, 0x0d,
/// # 0x77, 0xb3, 0xf9, 0x4d, 0x18, 0xfd, 0x10, 0xb6, 0xd8, 0x0e, 0x8b, 0xf8, 0x0f, 0x4a, 0x46, 0xca, 0xb0, 0x6d, 0x43, 0x13, 0xf0, 0xdb, 0x9b, 0xe9];
/// let alg = Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm);
/// let mut usage_flags: UsageFlags = Default::default();
/// usage_flags.set_decrypt();
/// let attributes = Attributes {
/// key_type: Type::Aes,
/// bits: 0,
/// lifetime: Lifetime::Volatile,
/// policy: Policy {
/// usage_flags,
/// permitted_algorithms: alg.into(),
/// },
/// };
/// psa_crypto::init().unwrap();
/// let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
/// let output_buffer_size = attributes.aead_decrypt_output_size(alg.into(), INPUT_DATA.len()).unwrap();
/// let mut output_buffer = vec![0; output_buffer_size];
/// let length = aead::decrypt(my_key, alg, &NONCE, &ADDITIONAL_DATA, &INPUT_DATA, &mut output_buffer).unwrap();
/// output_buffer.resize(length, 0);
/// ```
pub fn decrypt(
key_id: Id,
aead_alg: Aead,
nonce: &[u8],
additional_data: &[u8],
ciphertext: &[u8],
plaintext: &mut [u8],
) -> Result {
initialized()?;
let mut plaintext_size = 0;
Status::from(unsafe {
psa_crypto_sys::psa_aead_decrypt(
key_id.0,
aead_alg.into(),
nonce.as_ptr(),
nonce.len(),
additional_data.as_ptr(),
additional_data.len(),
ciphertext.as_ptr(),
ciphertext.len(),
plaintext.as_mut_ptr(),
plaintext.len(),
&mut plaintext_size,
)
})
.to_result()?;
Ok(plaintext_size)
}
psa-crypto-0.9.2/src/operations/asym_encryption.rs 0000644 0000000 0000000 00000013337 10461020230 0020507 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Asymmetric Encryption operations
//!
//! See the PSA Crypto API for the format of the different parameters used in this module.
use crate::initialized;
use crate::types::algorithm::AsymmetricEncryption;
use crate::types::key::Id;
use crate::types::status::{Result, Status};
/// Encrypt a short message with a key pair or public key
///
/// The encrypted message is written in `ciphertext`. The function returns the number of bytes written.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::key_management::generate;
/// # use psa_crypto::operations::asym_encryption::encrypt;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # use psa_crypto::types::algorithm::{AsymmetricEncryption, Hash};
/// #
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_encrypt();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into(),
/// # },
/// # };
/// # const MESSAGE: [u8; 32] = [
/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
/// # ];
/// psa_crypto::init().unwrap();
/// let my_key = generate(attributes, None).unwrap();
/// let alg = AsymmetricEncryption::RsaPkcs1v15Crypt;
/// let buffer_size = attributes.asymmetric_encrypt_output_size(alg).unwrap();
/// let mut encrypted_message = vec![0; buffer_size];
///
/// let size = encrypt(my_key,
/// alg,
/// &MESSAGE,
/// None,
/// &mut encrypted_message).unwrap();
/// encrypted_message.resize(size, 0);
/// ```
pub fn encrypt(
key_id: Id,
alg: AsymmetricEncryption,
plaintext: &[u8],
salt: Option<&[u8]>,
ciphertext: &mut [u8],
) -> Result {
initialized()?;
let mut output_length = 0;
let (salt_ptr, salt_len) = match salt {
Some(salt) => (salt.as_ptr(), salt.len()),
None => (core::ptr::null(), 0),
};
Status::from(unsafe {
psa_crypto_sys::psa_asymmetric_encrypt(
key_id.0,
alg.into(),
plaintext.as_ptr(),
plaintext.len(),
salt_ptr,
salt_len,
ciphertext.as_mut_ptr(),
ciphertext.len(),
&mut output_length,
)
})
.to_result()?;
Ok(output_length)
}
/// Decrypt a short message with a key pair or private key
///
/// The decrypted message is written in `plaintext`. The function returns the number of bytes written.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::key_management::{generate, export_public};
/// # use psa_crypto::operations::asym_encryption::decrypt;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # use psa_crypto::types::algorithm::{AsymmetricEncryption, Hash};
/// # use rsa::{RsaPublicKey, PaddingScheme, PublicKey};
/// # use rand::rngs::OsRng;
/// # use rsa::pkcs1::FromRsaPublicKey;
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_decrypt();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into()
/// # },
/// # };
/// # const MESSAGE: [u8; 64] = [ 0x4e, 0x31, 0x74, 0x96, 0x8f, 0xe4, 0xba, 0xb3, 0xaf, 0x77, 0x75,
/// # 0x76, 0x61, 0xde, 0xe5, 0xb8, 0x2c, 0x4f, 0x2a, 0x77, 0x6f, 0x2a, 0x86, 0x36, 0x13, 0xc3, 0xd1,
/// # 0x26, 0x77, 0x30, 0x64, 0x9c, 0xb9, 0x95, 0x84, 0x73, 0x54, 0xfd, 0x6d, 0x2f, 0xba, 0x7e, 0x6c,
/// # 0xb5, 0x0a, 0xe1, 0x09, 0x4e, 0x57, 0x3e, 0xeb, 0x7c, 0x64, 0xcc, 0x9d, 0xf2, 0xf2, 0x37, 0x2e,
/// # 0xb1, 0xe9, 0x92, 0xb7, 0x7b];
/// psa_crypto::init().unwrap();
///
/// let key_id = generate(attributes, None).unwrap();
/// let mut pub_key = vec![0; attributes.export_public_key_output_size().unwrap()];
/// let pub_key_length = export_public(key_id.clone(), &mut pub_key).unwrap();
/// pub_key.truncate(pub_key_length);
/// let rsa_pub_key = RsaPublicKey::from_pkcs1_der(&pub_key).unwrap();
/// let ciphertext = rsa_pub_key.encrypt(&mut OsRng, PaddingScheme::new_pkcs1v15_encrypt(), &MESSAGE).unwrap();
///
/// let alg = AsymmetricEncryption::RsaPkcs1v15Crypt;
/// let buffer_size = attributes.asymmetric_decrypt_output_size(alg).unwrap();
/// let mut decrypted_message = vec![0; buffer_size];
/// let size = decrypt(key_id,
/// alg,
/// &ciphertext,
/// None,
/// &mut decrypted_message).unwrap();
/// decrypted_message.resize(size, 0);
/// ```
pub fn decrypt(
key_id: Id,
alg: AsymmetricEncryption,
encrypted_message: &[u8],
salt: Option<&[u8]>,
plaintext: &mut [u8],
) -> Result {
initialized()?;
let mut output_length = 0;
let (salt_ptr, salt_len) = match salt {
Some(salt) => (salt.as_ptr(), salt.len()),
None => (core::ptr::null(), 0),
};
Status::from(unsafe {
psa_crypto_sys::psa_asymmetric_decrypt(
key_id.0,
alg.into(),
encrypted_message.as_ptr(),
encrypted_message.len(),
salt_ptr,
salt_len,
plaintext.as_mut_ptr(),
plaintext.len(),
&mut output_length,
)
})
.to_result()?;
Ok(output_length)
}
psa-crypto-0.9.2/src/operations/asym_signature.rs 0000644 0000000 0000000 00000011030 10461020230 0020302 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Asymmetric Signature operations
//!
//! See the PSA Crypto API for the format of the different parameters used in this module.
use crate::initialized;
use crate::types::algorithm::AsymmetricSignature;
use crate::types::key::Id;
use crate::types::status::{Result, Status};
/// Sign an already-calculated hash with a private key
///
/// The signature is written in `signature`. The function returns the number of bytes written.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::key_management::generate;
/// # use psa_crypto::operations::asym_signature::sign_hash;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
/// # const HASH: [u8; 32] = [
/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
/// # ];
/// psa_crypto::init().unwrap();
/// let my_key = generate(attributes, None).unwrap();
/// let alg = AsymmetricSignature::RsaPkcs1v15Sign {
/// hash_alg: Hash::Sha256.into(),
/// };
/// let buffer_size = attributes.sign_output_size(alg).unwrap();
/// let mut signature = vec![0; buffer_size];
///
/// let size = sign_hash(my_key,
/// alg,
/// &HASH,
/// &mut signature).unwrap();
/// signature.resize(size, 0);
/// ```
pub fn sign_hash(
key: Id,
alg: AsymmetricSignature,
hash: &[u8],
signature: &mut [u8],
) -> Result {
initialized()?;
let mut signature_length = 0;
Status::from(unsafe {
psa_crypto_sys::psa_sign_hash(
key.0,
alg.into(),
hash.as_ptr(),
hash.len(),
signature.as_mut_ptr(),
signature.len(),
&mut signature_length,
)
})
.to_result()?;
Ok(signature_length)
}
/// Verify the signature of a hash or short message using a public key
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::key_management::generate;
/// # use psa_crypto::operations::asym_signature::{sign_hash, verify_hash};
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
/// # const HASH: [u8; 32] = [
/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
/// # ];
/// psa_crypto::init().unwrap();
/// let alg = AsymmetricSignature::RsaPkcs1v15Sign {
/// hash_alg: Hash::Sha256.into(),
/// };
/// let buffer_size = attributes.sign_output_size(alg).unwrap();
/// let mut signature = vec![0; buffer_size];
/// let my_key = generate(attributes, None).unwrap();
/// let size = sign_hash(my_key,
/// alg,
/// &HASH,
/// &mut signature).unwrap();
/// signature.resize(size, 0);
/// verify_hash(my_key, alg, &HASH, &signature).unwrap();
/// ```
pub fn verify_hash(key: Id, alg: AsymmetricSignature, hash: &[u8], signature: &[u8]) -> Result<()> {
initialized()?;
Status::from(unsafe {
psa_crypto_sys::psa_verify_hash(
key.0,
alg.into(),
hash.as_ptr(),
hash.len(),
signature.as_ptr(),
signature.len(),
)
})
.to_result()
}
psa-crypto-0.9.2/src/operations/cipher.rs 0000644 0000000 0000000 00000011003 10461020230 0016522 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Unauthenticated Ciphers operations
use crate::initialized;
use crate::types::algorithm::Cipher;
use crate::types::key::Id;
use crate::types::status::{Result, Status};
fn crypt(
encrypt: bool,
key_id: Id,
alg: Cipher,
plaintext: &[u8],
iv: &[u8],
ciphertext: &mut [u8],
) -> Result {
initialized()?;
let mut operation: psa_crypto_sys::psa_cipher_operation_t =
unsafe { psa_crypto_sys::psa_cipher_operation_init() };
Status::from(unsafe {
(if encrypt {
psa_crypto_sys::psa_cipher_encrypt_setup
} else {
psa_crypto_sys::psa_cipher_decrypt_setup
})(&mut operation, key_id.0, alg.into())
})
.to_result()?;
let mut output_length = 0;
let mut output_length_finish = 0;
match (|| {
Status::from(unsafe {
psa_crypto_sys::psa_cipher_set_iv(&mut operation, iv.as_ptr(), iv.len())
})
.to_result()?;
Status::from(unsafe {
psa_crypto_sys::psa_cipher_update(
&mut operation,
plaintext.as_ptr(),
plaintext.len(),
ciphertext.as_mut_ptr(),
ciphertext.len(),
&mut output_length,
)
})
.to_result()?;
Status::from(unsafe {
psa_crypto_sys::psa_cipher_finish(
&mut operation,
ciphertext.as_mut_ptr().add(output_length),
ciphertext.len() - output_length,
&mut output_length_finish,
)
})
.to_result()?;
Ok(())
})() {
Ok(()) => (),
Err(x) => {
Status::from(unsafe { psa_crypto_sys::psa_cipher_abort(&mut operation) })
.to_result()?;
return Err(x);
}
}
Ok(output_length + output_length_finish)
}
/// Encrypt a short message with a key
///
/// The encrypted message is written in `ciphertext`. The function returns the number of bytes written.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::cipher::encrypt;
/// # use psa_crypto::operations::key_management::generate;
/// # use psa_crypto::types::algorithm::Cipher;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// #
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_encrypt();
/// # let mut attributes = Attributes {
/// # key_type: Type::Aes,
/// # bits: 128,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: Cipher::CbcNoPadding.into(),
/// # },
/// # };
/// # const MESSAGE: [u8; 16] = [0; 16];
/// psa_crypto::init().unwrap();
/// let my_key = generate(attributes, None).unwrap();
/// let alg = Cipher::CbcNoPadding;
/// let iv = vec![0; 16];
/// let mut encrypted_message = vec![0; MESSAGE.len()];
///
/// let size = encrypt(my_key, alg, &MESSAGE, &iv, &mut encrypted_message).unwrap();
/// ```
pub fn encrypt(
key_id: Id,
alg: Cipher,
plaintext: &[u8],
iv: &[u8],
ciphertext: &mut [u8],
) -> Result {
crypt(true, key_id, alg, plaintext, iv, ciphertext)
}
/// Decrypt a short message with a key
///
/// The decrypted message is written in `plaintext`. The function returns the number of bytes written.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::cipher::decrypt;
/// # use psa_crypto::operations::key_management::generate;
/// # use psa_crypto::types::algorithm::Cipher;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// #
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_decrypt();
/// # let mut attributes = Attributes {
/// # key_type: Type::Aes,
/// # bits: 128,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: Cipher::Ctr.into(),
/// # },
/// # };
/// # const MESSAGE: [u8; 13] = [0; 13];
/// psa_crypto::init().unwrap();
/// let my_key = generate(attributes, None).unwrap();
/// let alg = Cipher::Ctr;
/// let iv = vec![0; 16];
/// let mut decrypted_message = vec![0; MESSAGE.len()];
///
/// let size = decrypt(my_key, alg, &MESSAGE, &iv, &mut decrypted_message).unwrap();
/// ```
pub fn decrypt(
key_id: Id,
alg: Cipher,
ciphertext: &[u8],
iv: &[u8],
plaintext: &mut [u8],
) -> Result {
crypt(false, key_id, alg, ciphertext, iv, plaintext)
}
psa-crypto-0.9.2/src/operations/hash.rs 0000644 0000000 0000000 00000004625 10461020230 0016207 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Hash operations
//!
//! See the PSA Crypto API for the format of the different parameters used in this module.
use crate::initialized;
use crate::types::algorithm::Hash;
use crate::types::status::{Result, Status};
/// Calculate hash of a message
///
/// # Example
///
/// ```
/// use psa_crypto::operations::hash::hash_compute;
/// use psa_crypto::types::algorithm::Hash;
/// # const MESSAGE: [u8; 32] = [
/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
/// # ];
///
/// psa_crypto::init().unwrap();
/// let hash_alg = Hash::Sha256;
/// let mut hash = vec![0; hash_alg.hash_length()];
/// let size = hash_compute(hash_alg,
/// &MESSAGE,
/// &mut hash).unwrap();
/// ```
pub fn hash_compute(hash_alg: Hash, input: &[u8], hash: &mut [u8]) -> Result {
initialized()?;
let mut output_length = 0;
Status::from(unsafe {
psa_crypto_sys::psa_hash_compute(
hash_alg.into(),
input.as_ptr(),
input.len(),
hash.as_mut_ptr(),
hash.len(),
&mut output_length,
)
})
.to_result()?;
Ok(output_length)
}
/// Calculate the hash of a message and compare it with a reference value
///
/// # Example
///
/// ```
/// use psa_crypto::operations::hash::{hash_compute, hash_compare};
/// use psa_crypto::types::algorithm::Hash;
/// # const MESSAGE: [u8; 3] = [0xb0, 0xbd, 0x69];
/// # const HASH: [u8; 32] = [0x40, 0x96, 0x80, 0x42, 0x21, 0x09, 0x3d, 0xdc, 0xcf, 0xbf, 0x46, 0x83, 0x14, 0x90, 0xea, 0x63, 0xe9, 0xe9, 0x94, 0x14, 0x85, 0x8f, 0x8d, 0x75, 0xff, 0x7f, 0x64, 0x2c, 0x7c, 0xa6, 0x18, 0x03];
/// psa_crypto::init().unwrap();
/// let hash_alg = Hash::Sha256;
/// hash_compare(hash_alg,
/// &MESSAGE,
/// &HASH).unwrap();
/// ```
pub fn hash_compare(hash_alg: Hash, input: &[u8], hash_to_compare: &[u8]) -> Result<()> {
initialized()?;
Status::from(unsafe {
psa_crypto_sys::psa_hash_compare(
hash_alg.into(),
input.as_ptr(),
input.len(),
hash_to_compare.as_ptr(),
hash_to_compare.len(),
)
})
.to_result()
}
psa-crypto-0.9.2/src/operations/key_agreement.rs 0000644 0000000 0000000 00000005021 10461020230 0020072 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Key Agreement operations
use crate::initialized;
use crate::types::algorithm::RawKeyAgreement;
use crate::types::key::Id;
use crate::types::status::{Result, Status};
/// Perform a key agreement and return the raw shared secret.
/// # Example
///
/// ```
/// use psa_crypto::operations::{key_agreement, key_management};
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags, EccFamily};
/// use psa_crypto::types::algorithm::{KeyAgreement, RawKeyAgreement};
///
/// # const PEER_PUBLIC_KEY: [u8; 65] = [0x04, 0xd1, 0x2d, 0xfb, 0x52, 0x89, 0xc8, 0xd4, 0xf8, 0x12, 0x08, 0xb7, 0x02,
/// # 0x70, 0x39, 0x8c, 0x34, 0x22, 0x96, 0x97, 0x0a, 0x0b, 0xcc, 0xb7, 0x4c, 0x73, 0x6f, 0xc7, 0x55, 0x44, 0x94, 0xbf, 0x63,
/// # 0x56, 0xfb, 0xf3, 0xca, 0x36, 0x6c, 0xc2, 0x3e, 0x81, 0x57, 0x85, 0x4c, 0x13, 0xc5, 0x8d, 0x6a, 0xac, 0x23, 0xf0, 0x46,
/// # 0xad, 0xa3, 0x0f, 0x83, 0x53, 0xe7, 0x4f, 0x33, 0x03, 0x98, 0x72, 0xab];
///
///
/// # const OUR_KEY_DATA: [u8; 32] = [0xc8, 0x8f, 0x01, 0xf5, 0x10, 0xd9, 0xac, 0x3f, 0x70, 0xa2, 0x92, 0xda, 0xa2,
/// # 0x31, 0x6d, 0xe5, 0x44, 0xe9, 0xaa, 0xb8, 0xaf, 0xe8, 0x40, 0x49, 0xc6, 0x2a, 0x9c, 0x57, 0x86, 0x2d, 0x14, 0x33];
/// let alg = RawKeyAgreement::Ecdh;
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_derive();
/// # let attributes = Attributes {
/// # key_type: Type::EccKeyPair {curve_family: EccFamily::SecpR1 },
/// # bits: 256,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: KeyAgreement::Raw(alg).into(),
/// # },
/// # };
///
/// psa_crypto::init().unwrap();
/// let my_key = key_management::import(attributes, None, &OUR_KEY_DATA).unwrap();
/// let mut output = vec![0; attributes.raw_key_agreement_output_size(alg).unwrap()];
/// let size = key_agreement::raw_key_agreement(alg, my_key, &PEER_PUBLIC_KEY, &mut output).unwrap();
/// output.resize(size, 0);
/// ```
pub fn raw_key_agreement(
alg: RawKeyAgreement,
key_id: Id,
peer_key: &[u8],
output: &mut [u8],
) -> Result {
initialized()?;
let mut output_size = 0;
Status::from(unsafe {
psa_crypto_sys::psa_raw_key_agreement(
alg.into(),
key_id.0,
peer_key.as_ptr(),
peer_key.len(),
output.as_mut_ptr(),
output.len(),
&mut output_size,
)
})
.to_result()?;
Ok(output_size)
}
psa-crypto-0.9.2/src/operations/key_derivation.rs 0000644 0000000 0000000 00000006151 10461020230 0020274 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Key Derivation operations
use crate::initialized;
use crate::types::key::Attributes;
use crate::types::key::Id;
use crate::types::key_derivation::Operation;
use crate::types::status::{Error, Result, Status};
use core::convert::{TryFrom, TryInto};
/// This function calculates output bytes from a key derivation algorithm and uses those bytes to generate a key deterministically.
/// The key's location, usage policy, type and size are taken from attributes.
/// # Example
///
/// ```
/// use psa_crypto::operations::{key_derivation, key_management};
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{Hash, KeyDerivation};
/// use psa_crypto::types::key_derivation::{Operation, Inputs, Input, InputSecret};
///
/// # const KEY_DATA: [u8; 23] = [0; 23];
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_derive();
/// # let mut attributes = Attributes {
/// # key_type: Type::Derive,
/// # bits: 0,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: KeyDerivation::Hkdf {
/// # hash_alg: Hash::Sha256,
/// # }.into()
/// # }
/// # };
///
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_derive();
/// # let mut derived_key_attributes = Attributes {
/// # key_type: Type::RawData,
/// # bits: 8,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: KeyDerivation::Hkdf {
/// # hash_alg: Hash::Sha256,
/// # }.into()
/// # }
/// # };
///
/// psa_crypto::init().unwrap();
/// let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
/// let info = vec![20; 0x3f];
/// let mut operation = Operation {
/// inputs: Inputs::Hkdf {
/// hash_alg: Hash::Sha256,
/// salt: None,
/// secret: InputSecret::Input(Input::Key(my_key)),
/// info: Input::Bytes(&info),
/// },
/// capacity: None,
/// };
/// let _new_key = key_derivation::output_key(operation, derived_key_attributes, None).unwrap();
/// ```
pub fn output_key(operation: Operation, attributes: Attributes, id: Option) -> Result {
initialized()?;
let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?;
if let Some(id) = id {
unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) };
}
let mut id_for_new_key = 0;
let mut op: psa_crypto_sys::psa_key_derivation_operation_t = operation.try_into()?;
let key_deriv_res = Status::from(unsafe {
psa_crypto_sys::psa_key_derivation_output_key(&key_attributes, &mut op, &mut id_for_new_key)
})
.to_result();
if key_deriv_res == Err(Error::InsufficientData) {
key_deriv_res?;
} // InsufficientData is only error that does not require abort
Operation::abort(op)?;
key_deriv_res?; // All other error can now return after abort
Ok(Id(id_for_new_key))
}
psa-crypto-0.9.2/src/operations/key_management.rs 0000644 0000000 0000000 00000040507 10461020230 0020247 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Key Management operations
use crate::initialized;
use crate::types::key::{Attributes, Id};
use crate::types::status::{Result, Status};
use core::convert::TryFrom;
#[cfg(feature = "interface")]
use log::error;
/// Generate a key or a key pair
///
/// `id` can be set to `None` when creating a volatile key. Setting the `id` to something will
/// override the `lifetime` field of the attributes to `Lifetime::Persistent`.
/// When generating a persistent key with a
/// specific ID, the `Id` structure can be created after reset with the `from_persistent_key_id`
/// constructor on `Id`.
/// The `Id` structure returned can be used for cryptographic operations using that key.
///
/// # Example
///
/// ```
/// use psa_crypto::operations::key_management;
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
///
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
///
/// psa_crypto::init().unwrap();
/// let _my_key = key_management::generate(attributes, None).unwrap();
/// ```
pub fn generate(attributes: Attributes, id: Option) -> Result {
initialized()?;
let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?;
if let Some(id) = id {
unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) };
}
let mut id = 0;
Status::from(unsafe { psa_crypto_sys::psa_generate_key(&key_attributes, &mut id) })
.to_result()?;
Attributes::reset(&mut key_attributes);
Ok(Id(id))
}
/// Destroy a key
///
/// # Safety
///
/// It is unsafe to destroy a key that is concurrently used for any cryptographic operation. This
/// crate does not currently provide a mechanism to ensure thread safety of `destroy_key` but might
/// do in the future.
/// It is undefined behaviour to concurrently destroy and use a key.
///
/// This function can be safely called if the caller ensures that no other threads are concurrently
/// using copies of the same `Id` (that includes different `Id` instances that were created using
/// the same `id` parameter with the `from_persistent_key_id` function).
///
/// # Example
///
/// ```
/// use psa_crypto::operations::key_management;
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
///
/// psa_crypto::init().unwrap();
/// let my_key = key_management::generate(attributes, None).unwrap();
/// // Safe because no other threads is using this ID.
/// unsafe {key_management::destroy(my_key).unwrap() };
/// ```
pub unsafe fn destroy(key: Id) -> Result<()> {
initialized()?;
Status::from(psa_crypto_sys::psa_destroy_key(key.0)).to_result()
}
/// Import a key in binary format
///
/// `id` can be set to `None` when creating a volatile key. Setting the `id` to something will
/// override the `lifetime` field of the attributes to `Lifetime::Persistent`.
/// When generating a persistent key with a specific ID, the `Id` structure can be created after
/// reset with the `from_persistent_key_id` constructor on `Id`. Please check the PSA Crypto API
/// for a more complete description on the format expected in `data`. The `Id` structure returned
/// can be used for cryptographic operations using that key.
///
/// # Example
///
/// ```
/// # const KEY_DATA: [u8; 140] = [
/// # 48, 129, 137, 2, 129, 129, 0, 153, 165, 220, 135, 89, 101, 254, 229, 28, 33, 138, 247, 20, 102,
/// # 253, 217, 247, 246, 142, 107, 51, 40, 179, 149, 45, 117, 254, 236, 161, 109, 16, 81, 135, 72,
/// # 112, 132, 150, 175, 128, 173, 182, 122, 227, 214, 196, 130, 54, 239, 93, 5, 203, 185, 233, 61,
/// # 159, 156, 7, 161, 87, 48, 234, 105, 161, 108, 215, 211, 150, 168, 156, 212, 6, 63, 81, 24, 101,
/// # 72, 160, 97, 243, 142, 86, 10, 160, 122, 8, 228, 178, 252, 35, 209, 222, 228, 16, 143, 99, 143,
/// # 146, 241, 186, 187, 22, 209, 86, 141, 24, 159, 12, 146, 44, 111, 254, 183, 54, 229, 109, 28,
/// # 39, 22, 141, 173, 85, 26, 58, 9, 128, 27, 57, 131, 2, 3, 1, 0, 1,
/// # ];
/// use psa_crypto::operations::key_management;
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
///
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaPublicKey,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
///
/// psa_crypto::init().unwrap();
/// let _my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
/// ```
pub fn import(attributes: Attributes, id: Option, data: &[u8]) -> Result {
initialized()?;
let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?;
if let Some(id) = id {
unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) };
}
let mut id = 0;
Status::from(unsafe {
psa_crypto_sys::psa_import_key(&key_attributes, data.as_ptr(), data.len(), &mut id)
})
.to_result()?;
Attributes::reset(&mut key_attributes);
Ok(Id(id))
}
/// Export a public key or the public part of a key pair in binary format
///
/// The key is written in `data`. The functions returns the number of bytes written.
/// Please check the PSA Crypto API for a more complete description on the format of `data`.
///
/// # Example
///
/// ```
/// use psa_crypto::operations::key_management;
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
/// psa_crypto::init().unwrap();
/// let buffer_size = attributes.export_public_key_output_size().unwrap();
/// let mut data = vec![0; buffer_size];
/// let my_key = key_management::generate(attributes, None).unwrap();
/// let size = key_management::export_public(my_key, &mut data).unwrap();
/// data.resize(size, 0);
/// ```
pub fn export_public(key: Id, data: &mut [u8]) -> Result {
initialized()?;
let mut data_length = 0;
Status::from(unsafe {
psa_crypto_sys::psa_export_public_key(
key.0,
data.as_mut_ptr(),
data.len(),
&mut data_length,
)
})
.to_result()?;
Ok(data_length)
}
/// Export a key pair in binary format
///
/// The key is written in `data`. The function returns the number of bytes written.
/// Please check the PSA Crypto API for a more complete description on the format of `data`.
///
/// # Example
///
/// ```
/// use psa_crypto::operations::key_management;
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash().set_export();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
/// psa_crypto::init().unwrap();
/// let buffer_size = attributes.export_key_output_size().unwrap();
/// let mut data = vec![0; buffer_size];
/// let my_key = key_management::generate(attributes, None).unwrap();
/// let size = key_management::export(my_key, &mut data).unwrap();
/// data.resize(size, 0);
/// ```
pub fn export(key: Id, data: &mut [u8]) -> Result {
initialized()?;
let mut data_length = 0;
Status::from(unsafe {
psa_crypto_sys::psa_export_key(key.0, data.as_mut_ptr(), data.len(), &mut data_length)
})
.to_result()?;
Ok(data_length)
}
/// Copy key material from one location to another
/// The function returns the key ID of the newly created key `Id` can be set to `None` when creating a volatile key.
/// When generating a persistent key with a specific ID, the `Id` structure can be created after
/// reset with the `from_persistent_key_id` constructor on `Id`.
///
/// The originating key must have the usage flag `copy` set.
///
/// # Example
///
/// ```
/// use psa_crypto::operations::key_management;
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{AsymmetricSignature, Hash, Algorithm};
/// # let key_data = [0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xaf, 0x05, 0x7d, 0x39, 0x6e, 0xe8, 0x4f, 0xb7, 0x5f, 0xdb, 0xb5, 0xc2, 0xb1, 0x3c, 0x7f, 0xe5, 0xa6, 0x54, 0xaa, 0x8a, 0xa2, 0x47, 0x0b, 0x54, 0x1e, 0xe1, 0xfe, 0xb0, 0xb1, 0x2d, 0x25, 0xc7, 0x97, 0x11, 0x53, 0x12, 0x49, 0xe1, 0x12, 0x96, 0x28, 0x04, 0x2d, 0xbb, 0xb6, 0xc1, 0x20, 0xd1, 0x44, 0x35, 0x24, 0xef, 0x4c, 0x0e, 0x6e, 0x1d, 0x89, 0x56, 0xee, 0xb2, 0x07, 0x7a, 0xf1, 0x23, 0x49, 0xdd, 0xee, 0xe5, 0x44, 0x83, 0xbc, 0x06, 0xc2, 0xc6, 0x19, 0x48, 0xcd, 0x02, 0xb2, 0x02, 0xe7, 0x96, 0xae, 0xbd, 0x94, 0xd3, 0xa7, 0xcb, 0xf8, 0x59, 0xc2, 0xc1, 0x81, 0x9c, 0x32, 0x4c, 0xb8, 0x2b, 0x9c, 0xd3, 0x4e, 0xde, 0x26, 0x3a, 0x2a, 0xbf, 0xfe, 0x47, 0x33, 0xf0, 0x77, 0x86, 0x9e, 0x86, 0x60, 0xf7, 0xd6, 0x83, 0x4d, 0xa5, 0x3d, 0x69, 0x0e, 0xf7, 0x98, 0x5f, 0x6b, 0xc3, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x81, 0x00, 0x87, 0x4b, 0xf0, 0xff, 0xc2, 0xf2, 0xa7, 0x1d, 0x14, 0x67, 0x1d, 0xdd, 0x01, 0x71, 0xc9, 0x54, 0xd7, 0xfd, 0xbf, 0x50, 0x28, 0x1e, 0x4f, 0x6d, 0x99, 0xea, 0x0e, 0x1e, 0xbc, 0xf8, 0x2f, 0xaa, 0x58, 0xe7, 0xb5, 0x95, 0xff, 0xb2, 0x93, 0xd1, 0xab, 0xe1, 0x7f, 0x11, 0x0b, 0x37, 0xc4, 0x8c, 0xc0, 0xf3, 0x6c, 0x37, 0xe8, 0x4d, 0x87, 0x66, 0x21, 0xd3, 0x27, 0xf6, 0x4b, 0xbe, 0x08, 0x45, 0x7d, 0x3e, 0xc4, 0x09, 0x8b, 0xa2, 0xfa, 0x0a, 0x31, 0x9f, 0xba, 0x41, 0x1c, 0x28, 0x41, 0xed, 0x7b, 0xe8, 0x31, 0x96, 0xa8, 0xcd, 0xf9, 0xda, 0xa5, 0xd0, 0x06, 0x94, 0xbc, 0x33, 0x5f, 0xc4, 0xc3, 0x22, 0x17, 0xfe, 0x04, 0x88, 0xbc, 0xe9, 0xcb, 0x72, 0x02, 0xe5, 0x94, 0x68, 0xb1, 0xea, 0xd1, 0x19, 0x00, 0x04, 0x77, 0xdb, 0x2c, 0xa7, 0x97, 0xfa, 0xc1, 0x9e, 0xda, 0x3f, 0x58, 0xc1, 0x02, 0x41, 0x00, 0xe2, 0xab, 0x76, 0x08, 0x41, 0xbb, 0x9d, 0x30, 0xa8, 0x1d, 0x22, 0x2d, 0xe1, 0xeb, 0x73, 0x81, 0xd8, 0x22, 0x14, 0x40, 0x7f, 0x1b, 0x97, 0x5c, 0xbb, 0xfe, 0x4e, 0x1a, 0x94, 0x67, 0xfd, 0x98, 0xad, 0xbd, 0x78, 0xf6, 0x07, 0x83, 0x6c, 0xa5, 0xbe, 0x19, 0x28, 0xb9, 0xd1, 0x60, 0xd9, 0x7f, 0xd4, 0x5c, 0x12, 0xd6, 0xb5, 0x2e, 0x2c, 0x98, 0x71, 0xa1, 0x74, 0xc6, 0x6b, 0x48, 0x81, 0x13, 0x02, 0x41, 0x00, 0xc5, 0xab, 0x27, 0x60, 0x21, 0x59, 0xae, 0x7d, 0x6f, 0x20, 0xc3, 0xc2, 0xee, 0x85, 0x1e, 0x46, 0xdc, 0x11, 0x2e, 0x68, 0x9e, 0x28, 0xd5, 0xfc, 0xbb, 0xf9, 0x90, 0xa9, 0x9e, 0xf8, 0xa9, 0x0b, 0x8b, 0xb4, 0x4f, 0xd3, 0x64, 0x67, 0xe7, 0xfc, 0x17, 0x89, 0xce, 0xb6, 0x63, 0xab, 0xda, 0x33, 0x86, 0x52, 0xc3, 0xc7, 0x3f, 0x11, 0x17, 0x74, 0x90, 0x2e, 0x84, 0x05, 0x65, 0x92, 0x70, 0x91, 0x02, 0x41, 0x00, 0xb6, 0xcd, 0xbd, 0x35, 0x4f, 0x7d, 0xf5, 0x79, 0xa6, 0x3b, 0x48, 0xb3, 0x64, 0x3e, 0x35, 0x3b, 0x84, 0x89, 0x87, 0x77, 0xb4, 0x8b, 0x15, 0xf9, 0x4e, 0x0b, 0xfc, 0x05, 0x67, 0xa6, 0xae, 0x59, 0x11, 0xd5, 0x7a, 0xd6, 0x40, 0x9c, 0xf7, 0x64, 0x7b, 0xf9, 0x62, 0x64, 0xe9, 0xbd, 0x87, 0xeb, 0x95, 0xe2, 0x63, 0xb7, 0x11, 0x0b, 0x9a, 0x1f, 0x9f, 0x94, 0xac, 0xce, 0xd0, 0xfa, 0xfa, 0x4d, 0x02, 0x40, 0x71, 0x19, 0x5e, 0xec, 0x37, 0xe8, 0xd2, 0x57, 0xde, 0xcf, 0xc6, 0x72, 0xb0, 0x7a, 0xe6, 0x39, 0xf1, 0x0c, 0xbb, 0x9b, 0x0c, 0x73, 0x9d, 0x0c, 0x80, 0x99, 0x68, 0xd6, 0x44, 0xa9, 0x4e, 0x3f, 0xd6, 0xed, 0x92, 0x87, 0x07, 0x7a, 0x14, 0x58, 0x3f, 0x37, 0x90, 0x58, 0xf7, 0x6a, 0x8a, 0xec, 0xd4, 0x3c, 0x62, 0xdc, 0x8c, 0x0f, 0x41, 0x76, 0x66, 0x50, 0xd7, 0x25, 0x27, 0x5a, 0xc4, 0xa1, 0x02, 0x41, 0x00, 0xbb, 0x32, 0xd1, 0x33, 0xed, 0xc2, 0xe0, 0x48, 0xd4, 0x63, 0x38, 0x8b, 0x7b, 0xe9, 0xcb, 0x4b, 0xe2, 0x9f, 0x4b, 0x62, 0x50, 0xbe, 0x60, 0x3e, 0x70, 0xe3, 0x64, 0x75, 0x01, 0xc9, 0x7d, 0xdd, 0xe2, 0x0a, 0x4e, 0x71, 0xbe, 0x95, 0xfd, 0x5e, 0x71, 0x78, 0x4e, 0x25, 0xac, 0xa4, 0xba, 0xf2, 0x5b, 0xe5, 0x73, 0x8a, 0xae, 0x59, 0xbb, 0xfe, 0x1c, 0x99, 0x77, 0x81, 0x44, 0x7a, 0x2b, 0x24];
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_copy().set_export();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: Algorithm::None,
/// # },
/// # };
/// psa_crypto::init().unwrap();
/// let my_key = key_management::import(attributes, None, &key_data).unwrap();
/// let my_key_copy = key_management::copy(my_key, attributes, None).unwrap();
/// ```
pub fn copy(key_id_to_copy: Id, attributes: Attributes, id: Option) -> Result {
initialized()?;
let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?;
if let Some(id) = id {
unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) };
}
let mut new_id = 0;
let copy_res = Status::from(unsafe {
psa_crypto_sys::psa_copy_key(key_id_to_copy.0, &key_attributes, &mut new_id)
})
.to_result();
Attributes::reset(&mut key_attributes);
copy_res?;
Ok(Id(new_id))
}
/// Remove non-essential copies of key material from memory
///
/// This function will remove these extra copies of the key material from memory.
///
/// This function is not required to remove key material from memory in any of the following situations:
/// The key is currently in use in a cryptographic operation.
/// The key is volatile.
///
/// # Example
///
/// ```
/// use psa_crypto::operations::key_management;
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_cache();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
/// psa_crypto::init().unwrap();
/// //let my_key = key_management::generate(attributes, None).unwrap();
/// //let size = key_management::purge(my_key).unwrap();
/// ```
pub fn purge(/*key_id: Id*/) /*-> Result<()>*/
{
error!("This operation is not yet supported by Mbed Crypto. Once it is supported, uncomment and remove this notice");
// Also uncomment the example
/*initialized()?;
let handle = key_id.handle()?;
let purge_res = Status::from(psa_crypto_sys::psa_purge_key(handle)).to_result()
let close_handle_res = key_id.close_handle(handle);
purge_res?;
close_handle_res*/
}
psa-crypto-0.9.2/src/operations/mac.rs 0000644 0000000 0000000 00000010774 10461020230 0016026 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Message Authentication Code (MAC) operations
use crate::initialized;
use crate::types::key::Id;
use crate::types::algorithm::Mac;
use crate::types::status::{Result, Status, Error};
/// Calculate the message authentication code (MAC) of a message
/// The key must allow `sign_message`
///
/// # Example
///
/// ```
/// use psa_crypto::operations::{mac::compute_mac, key_management::generate};
/// use psa_crypto::types::algorithm::{Hash, Mac, FullLengthMac};
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # const MESSAGE: [u8; 32] = [
/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
/// # ];
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags: UsageFlags {
/// # sign_message: true,
/// # ..Default::default()
/// # },
/// # permitted_algorithms: FullLengthMac::Hmac{hash_alg: Hash::Sha256}.into(),
/// # },
/// # };
/// #
/// psa_crypto::init().unwrap();
/// let my_key = generate(attributes, None).unwrap();
/// let mac_alg = Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256});
/// let buffer_size = attributes.mac_length(mac_alg).unwrap();
/// let mut mac = vec![0; buffer_size];
///
/// let size = compute_mac(my_key,
/// mac_alg,
/// &MESSAGE,
/// &mut mac).unwrap();
/// mac.resize(size, 0);
/// ```
pub fn compute_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], mac: &mut [u8]) -> Result {
initialized()?;
let mut output_length = 0;
let key_handle = key_id.handle()?;
let mac_compute_res = Status::from(unsafe {
psa_crypto_sys::psa_mac_compute(
key_handle,
mac_alg.into(),
input_message.as_ptr(),
input_message.len(),
mac.as_mut_ptr(),
mac.len(),
&mut output_length,
)}
).to_result();
let close_handle_res = key_id.close_handle(key_handle);
mac_compute_res?;
close_handle_res?;
Ok(output_length)
}
/// Calculate the message authentication code (MAC) of a message and compare it with a reference value
/// The key must allow `sign_message`
///
/// # Example
///
/// ```
/// use psa_crypto::operations::{mac::{compute_mac, verify_mac}, key_management::generate};
/// use psa_crypto::types::algorithm::{Hash, Mac, FullLengthMac};
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # const MESSAGE: [u8; 32] = [
/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
/// # ];
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags: UsageFlags {
/// # sign_message: true,
/// # ..Default::default()
/// # },
/// # permitted_algorithms: Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256}).into(),
/// # },
/// # };
/// #
/// psa_crypto::init().unwrap();
/// let my_key = generate(attributes, None).unwrap();
/// let mac_alg = Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256});
/// let buffer_size = attributes.mac_length(mac_alg).unwrap();
/// let mut mac = vec![0; buffer_size];
///
/// let size = compute_mac(my_key,
/// mac_alg,
/// &MESSAGE,
/// &mut mac).unwrap();
/// mac.resize(size, 0);
/// assert!(verify_mac(my_key, mac_alg, &MESSAGE, &mac));
/// ```
pub fn verify_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], expected_mac: &[u8]) -> Result<()> {
initialized()?;
let key_handle = key_id.handle()?;
let mac_verify_res = Status::from(unsafe {
psa_crypto_sys::psa_mac_verify(
key_handle,
mac_alg.into(),
input_message.as_ptr(),
input_message.len(),
expected_mac.as_ptr(),
expected_mac.len(),
)}
).to_result();
let close_handle_res = key_id.close_handle(key_handle);
mac_verify_res?;
close_handle_res
} psa-crypto-0.9.2/src/operations/message_digest.rs 0000644 0000000 0000000 00000000176 10461020230 0020244 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Message digest operations
psa-crypto-0.9.2/src/operations/mod.rs 0000644 0000000 0000000 00000000626 10461020230 0016040 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PSA Operations
pub mod aead;
pub mod asym_encryption;
pub mod asym_signature;
pub mod cipher;
pub mod key_agreement;
pub mod key_derivation;
pub mod key_management;
//pub mod mac; Mbed Crypto does not support mac compute or verify yet (as of 16/07/20)
pub mod hash;
pub mod message_digest;
pub mod other;
psa-crypto-0.9.2/src/operations/other.rs 0000644 0000000 0000000 00000001660 10461020230 0016401 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # Other cryptographic services
//!
//! See the PSA Crypto API for the format of the different parameters used in this module.
use crate::initialized;
use crate::types::status::{Result, Status};
/// Generate a buffer of random bytes.
///
/// The random bytes are written into `output`. The function returns a result based on whether the
/// operation succeeded or failed.
///
/// Example:
///
/// ```
/// use psa_crypto::operations::other::generate_random;
///
/// psa_crypto::init().unwrap();
/// const BUFFER_SIZE: usize = 16;
/// let mut buffer = vec![0u8; BUFFER_SIZE];
/// let result = generate_random(&mut buffer);
/// ```
pub fn generate_random(output: &mut [u8]) -> Result<()> {
initialized()?;
Status::from(unsafe { psa_crypto_sys::psa_generate_random(output.as_mut_ptr(), output.len()) })
.to_result()?;
Ok(())
}
psa-crypto-0.9.2/src/types/algorithm.rs 0000644 0000000 0000000 00000114560 10461020230 0016233 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PSA Algorithms
#![allow(deprecated)]
#[cfg(feature = "interface")]
use crate::types::status::{Error, Result};
#[cfg(feature = "interface")]
use core::convert::{TryFrom, TryInto};
#[cfg(feature = "interface")]
use log::error;
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
/// Enumeration of possible algorithm definitions.
/// Each variant of the enum contains a main algorithm type (which is required for
/// that variant).
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum Algorithm {
/// An invalid algorithm identifier value.
/// `None` does not allow any cryptographic operation with the key. The key can still be
/// used for non-cryptographic actions such as exporting, if permitted by the usage flags.
None,
/// Hash algorithm.
Hash(Hash),
/// MAC algorithm.
Mac(Mac),
/// Symmetric Cipher algorithm.
Cipher(Cipher),
/// Authenticated Encryption with Associated Data (AEAD) algorithm.
Aead(Aead),
/// Public-key signature algorithm.
AsymmetricSignature(AsymmetricSignature),
/// Public-key encryption algorithm.
AsymmetricEncryption(AsymmetricEncryption),
/// Key agreement algorithm.
KeyAgreement(KeyAgreement),
/// Key derivation algorithm.
KeyDerivation(KeyDerivation),
}
impl Algorithm {
/// Check if the algorithm is a HMAC algorithm, truncated or not
///
/// # Example
///
/// ```
/// use psa_crypto::types::algorithm::{Algorithm, Mac, FullLengthMac, Hash};
/// let hmac = Algorithm::Mac(Mac::Truncated {
/// mac_alg: FullLengthMac::Hmac { hash_alg: Hash::Sha256 },
/// mac_length: 30,
/// });
/// assert!(hmac.is_hmac());
/// ```
pub fn is_hmac(self) -> bool {
match self {
Algorithm::Mac(mac_alg) => mac_alg.is_hmac(),
_ => false,
}
}
}
/// Enumeration of hash algorithms supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
#[allow(deprecated)]
pub enum Hash {
/// MD2
#[deprecated = "The MD2 hash is weak and deprecated and is only recommended for use in legacy protocols."]
Md2,
/// MD4
#[deprecated = "The MD4 hash is weak and deprecated and is only recommended for use in legacy protocols."]
Md4,
/// MD5
#[deprecated = "The MD5 hash is weak and deprecated and is only recommended for use in legacy protocols."]
Md5,
/// RIPEMD-160
Ripemd160,
/// SHA-1
#[deprecated = "The SHA-1 hash is weak and deprecated and is only recommended for use in legacy protocols."]
Sha1,
/// SHA-224
Sha224,
/// SHA-256
Sha256,
/// SHA-384
Sha384,
/// SHA-512
Sha512,
/// SHA-512/224
Sha512_224,
/// SHA-512/256
Sha512_256,
/// SHA3-224
Sha3_224,
/// SHA3-256
Sha3_256,
/// SHA3-384
Sha3_384,
/// SHA3-512
Sha3_512,
}
impl Hash {
/// Get the digest size output by the hash algorithm in bytes
///
/// # Example
///
/// ```
/// use psa_crypto::types::algorithm::Hash;
/// assert_eq!(Hash::Sha256.hash_length(), 32);
/// assert_eq!(Hash::Sha512.hash_length(), 64);
/// ```
pub fn hash_length(self) -> usize {
match self {
Hash::Md2 | Hash::Md4 | Hash::Md5 => 16,
Hash::Ripemd160 | Hash::Sha1 => 20,
Hash::Sha224 | Hash::Sha512_224 | Hash::Sha3_224 => 28,
Hash::Sha256 | Hash::Sha512_256 | Hash::Sha3_256 => 32,
Hash::Sha384 | Hash::Sha3_384 => 48,
Hash::Sha3_512 | Hash::Sha512 => 64,
}
}
}
/// Enumeration of untruncated MAC algorithms.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum FullLengthMac {
/// HMAC algorithm
Hmac {
/// Hash algorithm to use.
hash_alg: Hash,
},
/// The CBC-MAC construction over a block cipher.
CbcMac,
/// The CMAC construction over a block cipher.
Cmac,
}
/// Enumeration of message authentication code algorithms supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum Mac {
/// Untruncated MAC algorithm
FullLength(FullLengthMac),
/// Truncated MAC algorithm
Truncated {
/// The MAC algorithm to truncate.
mac_alg: FullLengthMac,
/// Desired length of the truncated MAC in bytes.
mac_length: usize,
},
}
impl Mac {
/// Check if the MAC algorithm is a HMAC algorithm, truncated or not
pub fn is_hmac(self) -> bool {
matches!(
self,
Mac::FullLength(FullLengthMac::Hmac { .. })
| Mac::Truncated {
mac_alg: FullLengthMac::Hmac { .. },
..
}
)
}
/// Check if the MAC algorithm is a construction over a block cipher
pub fn is_block_cipher_needed(self) -> bool {
matches!(
self,
Mac::FullLength(FullLengthMac::CbcMac)
| Mac::FullLength(FullLengthMac::Cmac)
| Mac::Truncated {
mac_alg: FullLengthMac::CbcMac,
..
}
| Mac::Truncated {
mac_alg: FullLengthMac::Cmac,
..
}
)
}
}
/// Enumeration of symmetric encryption algorithms supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum Cipher {
/// The stream cipher mode of a stream cipher algorithm.
StreamCipher,
/// A stream cipher built using the Counter (CTR) mode of a block cipher.
Ctr,
/// A stream cipher built using the Cipher Feedback (CFB) mode of a block cipher.
Cfb,
/// A stream cipher built using the Output Feedback (OFB) mode of a block cipher.
Ofb,
/// The XTS cipher mode of a block cipher.
Xts,
/// The Electronic Code Book (ECB) mode of a block cipher, with no padding.
EcbNoPadding,
/// The Cipher Block Chaining (CBC) mode of a block cipher, with no padding.
CbcNoPadding,
/// The Cipher Block Chaining (CBC) mode of a block cipher, with PKCS#7 padding.
CbcPkcs7,
}
impl Cipher {
/// Check is the cipher algorithm is a mode of a block cipher.
pub fn is_block_cipher_mode(self) -> bool {
matches!(
self,
Cipher::Ctr
| Cipher::Cfb
| Cipher::Ofb
| Cipher::Xts
| Cipher::EcbNoPadding
| Cipher::CbcNoPadding
| Cipher::CbcPkcs7
)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
/// AEAD algorithm with default length tag enumeration
pub enum AeadWithDefaultLengthTag {
/// The CCM authenticated encryption algorithm.
Ccm,
/// The GCM authenticated encryption algorithm.
Gcm,
/// The Chacha20-Poly1305 AEAD algorithm.
Chacha20Poly1305,
}
/// Enumeration of authenticated encryption with additional data algorithms
/// supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum Aead {
/// AEAD algorithm with a default length tag
AeadWithDefaultLengthTag(AeadWithDefaultLengthTag),
/// AEAD algorithm with a shortened tag.
AeadWithShortenedTag {
/// An AEAD algorithm.
aead_alg: AeadWithDefaultLengthTag,
/// Desired length of the authentication tag in bytes.
tag_length: usize,
},
}
impl Aead {
/// Check if the Aead algorithm needs a block cipher
pub fn is_aead_on_block_cipher(self) -> bool {
matches!(
self,
Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm)
| Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Gcm)
| Aead::AeadWithShortenedTag {
aead_alg: AeadWithDefaultLengthTag::Ccm,
..
}
| Aead::AeadWithShortenedTag {
aead_alg: AeadWithDefaultLengthTag::Gcm,
..
}
)
}
/// Check if this AEAD algorithm is the (truncated or not) Chacha20-Poly1305 AEAD algorithm.
pub fn is_chacha20_poly1305_alg(self) -> bool {
matches!(
self,
Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Chacha20Poly1305)
| Aead::AeadWithShortenedTag {
aead_alg: AeadWithDefaultLengthTag::Chacha20Poly1305,
..
}
)
}
}
/// Enumeration of hash algorithms used in "hash-and-sign" algorithms.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum SignHash {
/// A specific hash algorithm to choose.
Specific(Hash),
/// In a hash-and-sign algorithm policy, allow any hash algorithm. This value must not be used
/// to build an algorithm specification to perform an operation. It is only valid to build
/// policies, for signature algorithms.
Any,
}
impl SignHash {
/// Check if the alg given for a cryptographic operation is permitted to be used with this
/// algorithm as a policy
pub fn is_alg_permitted(self, alg: SignHash) -> bool {
if let SignHash::Specific(_) = alg {
if self == SignHash::Any {
true
} else {
self == alg
}
} else {
// Any is not permitted for a cryptographic operation
false
}
}
}
impl From for SignHash {
fn from(hash: Hash) -> Self {
SignHash::Specific(hash)
}
}
/// Enumeration of asymmetric signing algorithms supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum AsymmetricSignature {
/// RSA PKCS#1 v1.5 signature with hashing.
RsaPkcs1v15Sign {
/// A hash algorithm to use.
hash_alg: SignHash,
},
/// Raw PKCS#1 v1.5 signature.
RsaPkcs1v15SignRaw,
/// RSA PSS signature with hashing.
RsaPss {
/// A hash algorithm to use.
hash_alg: SignHash,
},
/// ECDSA signature with hashing.
Ecdsa {
/// A hash algorithm to use.
hash_alg: SignHash,
},
/// ECDSA signature without hashing.
EcdsaAny,
/// Deterministic ECDSA signature with hashing.
DeterministicEcdsa {
/// A hash algorithm to use.
hash_alg: SignHash,
},
}
impl AsymmetricSignature {
/// Check if the alg given for a cryptographic operation is permitted to be used with this
/// algorithm as a policy
///
/// # Example
///
/// ```
/// use psa_crypto::types::algorithm::{AsymmetricSignature, SignHash, Hash};
/// assert!(AsymmetricSignature::RsaPkcs1v15Sign { hash_alg: SignHash::Any }
/// .is_alg_permitted(AsymmetricSignature::RsaPkcs1v15Sign {
/// hash_alg: SignHash::Specific(Hash::Sha1)
/// })
/// );
/// assert!(!AsymmetricSignature::RsaPkcs1v15Sign { hash_alg: SignHash::Specific(Hash::Sha256) }
/// .is_alg_permitted(AsymmetricSignature::RsaPkcs1v15Sign {
/// hash_alg: SignHash::Specific(Hash::Sha1)
/// })
/// );
/// ```
pub fn is_alg_permitted(self, alg: AsymmetricSignature) -> bool {
match self {
AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: hash_policy,
} => {
if let AsymmetricSignature::RsaPkcs1v15Sign { hash_alg } = alg {
hash_policy.is_alg_permitted(hash_alg)
} else {
false
}
}
AsymmetricSignature::RsaPss {
hash_alg: hash_policy,
} => {
if let AsymmetricSignature::RsaPss { hash_alg } = alg {
hash_policy.is_alg_permitted(hash_alg)
} else {
false
}
}
AsymmetricSignature::Ecdsa {
hash_alg: hash_policy,
} => {
if let AsymmetricSignature::Ecdsa { hash_alg } = alg {
hash_policy.is_alg_permitted(hash_alg)
} else {
false
}
}
AsymmetricSignature::DeterministicEcdsa {
hash_alg: hash_policy,
} => {
if let AsymmetricSignature::DeterministicEcdsa { hash_alg } = alg {
hash_policy.is_alg_permitted(hash_alg)
} else {
false
}
}
// These ones can not be wildcard algorithms
asymmetric_signature_alg => asymmetric_signature_alg == alg,
}
}
/// Check if this is a RSA algorithm
pub fn is_rsa_alg(self) -> bool {
matches!(
self,
AsymmetricSignature::RsaPkcs1v15Sign { .. }
| AsymmetricSignature::RsaPkcs1v15SignRaw
| AsymmetricSignature::RsaPss { .. }
)
}
/// Check if this is an ECC algorithm
pub fn is_ecc_alg(self) -> bool {
matches!(
self,
AsymmetricSignature::Ecdsa { .. }
| AsymmetricSignature::EcdsaAny
| AsymmetricSignature::DeterministicEcdsa { .. }
)
}
/// Determines if the given hash length is compatible with the asymmetric signature scheme
pub fn is_hash_len_permitted(self, hash_len: usize) -> bool {
match self {
AsymmetricSignature::EcdsaAny | AsymmetricSignature::RsaPkcs1v15SignRaw => true,
AsymmetricSignature::DeterministicEcdsa { hash_alg }
| AsymmetricSignature::RsaPkcs1v15Sign { hash_alg }
| AsymmetricSignature::Ecdsa { hash_alg }
| AsymmetricSignature::RsaPss { hash_alg } => {
if let SignHash::Specific(hash_alg) = hash_alg {
hash_alg.hash_length() == hash_len
} else {
false
}
}
}
}
/// Retrieves the specific hash that the `AsymmetricSignature` algorithm is restricted to.
///
/// For algorithms that do not specify a hash, `None` is returned.
pub fn hash(self) -> Option {
match self {
AsymmetricSignature::EcdsaAny | AsymmetricSignature::RsaPkcs1v15SignRaw => None,
AsymmetricSignature::DeterministicEcdsa { hash_alg }
| AsymmetricSignature::RsaPkcs1v15Sign { hash_alg }
| AsymmetricSignature::Ecdsa { hash_alg }
| AsymmetricSignature::RsaPss { hash_alg } => Some(hash_alg),
}
}
}
/// Enumeration of asymmetric encryption algorithms supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum AsymmetricEncryption {
/// RSA PKCS#1 v1.5 encryption.
RsaPkcs1v15Crypt,
/// RSA OAEP encryption.
RsaOaep {
/// A hash algorithm to use.
hash_alg: Hash,
},
}
/// Key agreement algorithm enumeration.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum RawKeyAgreement {
/// The finite-field Diffie-Hellman (DH) key agreement algorithm.
Ffdh,
/// The elliptic curve Diffie-Hellman (ECDH) key agreement algorithm.
Ecdh,
}
/// Enumeration of key agreement algorithms supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum KeyAgreement {
/// Key agreement only algorithm.
Raw(RawKeyAgreement),
/// Build a combined algorithm that chains a key agreement with a key derivation.
WithKeyDerivation {
/// A key agreement algorithm.
ka_alg: RawKeyAgreement,
/// A key derivation algorithm.
kdf_alg: KeyDerivation,
},
}
/// Enumeration of key derivation functions supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum KeyDerivation {
/// HKDF algorithm.
Hkdf {
/// A hash algorithm to use.
hash_alg: Hash,
},
/// TLS-1.2 PRF algorithm.
Tls12Prf {
/// A hash algorithm to use.
hash_alg: Hash,
},
/// TLS-1.2 PSK-to-MasterSecret algorithm.
Tls12PskToMs {
/// A hash algorithm to use.
hash_alg: Hash,
},
}
impl From for Algorithm {
fn from(alg: Hash) -> Self {
Algorithm::Hash(alg)
}
}
impl From for Algorithm {
fn from(alg: Mac) -> Self {
Algorithm::Mac(alg)
}
}
impl From for Algorithm {
fn from(alg: Cipher) -> Self {
Algorithm::Cipher(alg)
}
}
impl From for Algorithm {
fn from(alg: Aead) -> Self {
Algorithm::Aead(alg)
}
}
impl From for Algorithm {
fn from(alg: AsymmetricSignature) -> Self {
Algorithm::AsymmetricSignature(alg)
}
}
impl From for Algorithm {
fn from(alg: AsymmetricEncryption) -> Self {
Algorithm::AsymmetricEncryption(alg)
}
}
impl From for Algorithm {
fn from(alg: KeyAgreement) -> Self {
Algorithm::KeyAgreement(alg)
}
}
impl From for Algorithm {
fn from(alg: KeyDerivation) -> Self {
Algorithm::KeyDerivation(alg)
}
}
#[cfg(feature = "interface")]
impl TryFrom for Algorithm {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if alg == 0 {
Ok(Algorithm::None)
} else if psa_crypto_sys::PSA_ALG_IS_HASH(alg) {
let hash: Hash = alg.try_into()?;
Ok(hash.into())
} else if psa_crypto_sys::PSA_ALG_IS_MAC(alg) {
let mac: Mac = alg.try_into()?;
Ok(mac.into())
} else if psa_crypto_sys::PSA_ALG_IS_CIPHER(alg) {
error!("Cipher algorithms are not supported.");
Err(Error::NotSupported)
} else if psa_crypto_sys::PSA_ALG_IS_AEAD(alg) {
let aead: Aead = alg.try_into()?;
Ok(aead.into())
} else if psa_crypto_sys::PSA_ALG_IS_SIGN(alg) {
let asym_sign: AsymmetricSignature = alg.try_into()?;
Ok(asym_sign.into())
} else if psa_crypto_sys::PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg) {
let asym_encryption: AsymmetricEncryption = alg.try_into()?;
Ok(asym_encryption.into())
} else if psa_crypto_sys::PSA_ALG_IS_KEY_AGREEMENT(alg) {
let key_agreement: KeyAgreement = alg.try_into()?;
Ok(key_agreement.into())
} else if psa_crypto_sys::PSA_ALG_IS_KEY_DERIVATION(alg) {
let key_derivation: KeyDerivation = alg.try_into()?;
Ok(key_derivation.into())
} else {
error!("Can not find a valid Algorithm for {}.", alg);
Err(Error::NotSupported)
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for psa_crypto_sys::psa_algorithm_t {
type Error = Error;
fn try_from(alg: Algorithm) -> Result {
match alg {
Algorithm::None => Ok(0),
Algorithm::Hash(hash) => Ok(hash.into()),
Algorithm::AsymmetricSignature(asym_sign) => Ok(asym_sign.into()),
Algorithm::AsymmetricEncryption(asym_encrypt) => Ok(asym_encrypt.into()),
Algorithm::Mac(mac) => Ok(mac.into()),
Algorithm::KeyAgreement(key_agreement) => Ok(key_agreement.into()),
Algorithm::KeyDerivation(key_derivation) => Ok(key_derivation.into()),
Algorithm::Aead(aead) => Ok(aead.into()),
Algorithm::Cipher(cipher) => Ok(cipher.into()),
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for Hash {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
match alg {
psa_crypto_sys::PSA_ALG_MD2 => Ok(Hash::Md2),
psa_crypto_sys::PSA_ALG_MD4 => Ok(Hash::Md4),
psa_crypto_sys::PSA_ALG_MD5 => Ok(Hash::Md5),
psa_crypto_sys::PSA_ALG_RIPEMD160 => Ok(Hash::Ripemd160),
psa_crypto_sys::PSA_ALG_SHA_1 => Ok(Hash::Sha1),
psa_crypto_sys::PSA_ALG_SHA_224 => Ok(Hash::Sha224),
psa_crypto_sys::PSA_ALG_SHA_256 => Ok(Hash::Sha256),
psa_crypto_sys::PSA_ALG_SHA_384 => Ok(Hash::Sha384),
psa_crypto_sys::PSA_ALG_SHA_512 => Ok(Hash::Sha512),
psa_crypto_sys::PSA_ALG_SHA_512_224 => Ok(Hash::Sha512_224),
psa_crypto_sys::PSA_ALG_SHA_512_256 => Ok(Hash::Sha512_256),
psa_crypto_sys::PSA_ALG_SHA3_224 => Ok(Hash::Sha3_224),
psa_crypto_sys::PSA_ALG_SHA3_256 => Ok(Hash::Sha3_256),
psa_crypto_sys::PSA_ALG_SHA3_384 => Ok(Hash::Sha3_384),
psa_crypto_sys::PSA_ALG_SHA3_512 => Ok(Hash::Sha3_512),
a => {
error!("Can not find a valid Hash algorithm for {}.", a);
Err(Error::InvalidArgument)
}
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(hash: Hash) -> Self {
match hash {
Hash::Md2 => psa_crypto_sys::PSA_ALG_MD2,
Hash::Md4 => psa_crypto_sys::PSA_ALG_MD4,
Hash::Md5 => psa_crypto_sys::PSA_ALG_MD5,
Hash::Ripemd160 => psa_crypto_sys::PSA_ALG_RIPEMD160,
Hash::Sha1 => psa_crypto_sys::PSA_ALG_SHA_1,
Hash::Sha224 => psa_crypto_sys::PSA_ALG_SHA_224,
Hash::Sha256 => psa_crypto_sys::PSA_ALG_SHA_256,
Hash::Sha384 => psa_crypto_sys::PSA_ALG_SHA_384,
Hash::Sha512 => psa_crypto_sys::PSA_ALG_SHA_512,
Hash::Sha512_224 => psa_crypto_sys::PSA_ALG_SHA_512_224,
Hash::Sha512_256 => psa_crypto_sys::PSA_ALG_SHA_512_256,
Hash::Sha3_224 => psa_crypto_sys::PSA_ALG_SHA3_224,
Hash::Sha3_256 => psa_crypto_sys::PSA_ALG_SHA3_256,
Hash::Sha3_384 => psa_crypto_sys::PSA_ALG_SHA3_384,
Hash::Sha3_512 => psa_crypto_sys::PSA_ALG_SHA3_512,
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for SignHash {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if alg == psa_crypto_sys::PSA_ALG_ANY_HASH {
Ok(SignHash::Any)
} else {
Ok(SignHash::Specific(alg.try_into()?))
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(sign_hash: SignHash) -> Self {
match sign_hash {
SignHash::Specific(hash) => hash.into(),
SignHash::Any => psa_crypto_sys::PSA_ALG_ANY_HASH,
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for AsymmetricSignature {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if alg == psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN_RAW {
Ok(AsymmetricSignature::RsaPkcs1v15SignRaw)
} else if alg == psa_crypto_sys::PSA_ALG_ECDSA_ANY {
Ok(AsymmetricSignature::EcdsaAny)
} else if psa_crypto_sys::PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) {
Ok(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
})
} else if psa_crypto_sys::PSA_ALG_IS_RSA_PSS(alg) {
Ok(AsymmetricSignature::RsaPss {
hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
})
} else if psa_crypto_sys::PSA_ALG_IS_ECDSA(alg) {
Ok(AsymmetricSignature::Ecdsa {
hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
})
} else if psa_crypto_sys::PSA_ALG_IS_DETERMINISTIC_ECDSA(alg) {
Ok(AsymmetricSignature::DeterministicEcdsa {
hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
})
} else {
error!(
"Can not find a valid AsymmetricSignature algorithm for {}.",
alg
);
Err(Error::InvalidArgument)
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(asym_sign: AsymmetricSignature) -> Self {
match asym_sign {
AsymmetricSignature::RsaPkcs1v15Sign { hash_alg } => {
psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg.into())
}
AsymmetricSignature::RsaPkcs1v15SignRaw => {
psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN_RAW
}
AsymmetricSignature::RsaPss { hash_alg } => {
psa_crypto_sys::PSA_ALG_RSA_PSS(hash_alg.into())
}
AsymmetricSignature::Ecdsa { hash_alg } => {
psa_crypto_sys::PSA_ALG_ECDSA(hash_alg.into())
}
AsymmetricSignature::EcdsaAny => psa_crypto_sys::PSA_ALG_ECDSA_ANY,
AsymmetricSignature::DeterministicEcdsa { hash_alg } => {
psa_crypto_sys::PSA_ALG_DETERMINISTIC_ECDSA(hash_alg.into())
}
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for AsymmetricEncryption {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if alg == psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_CRYPT {
Ok(AsymmetricEncryption::RsaPkcs1v15Crypt)
} else if unsafe { psa_crypto_sys::PSA_ALG_IS_RSA_OAEP(alg) } {
Ok(AsymmetricEncryption::RsaOaep {
hash_alg: psa_crypto_sys::PSA_ALG_RSA_OAEP_GET_HASH(alg).try_into()?,
})
} else {
error!(
"Can not find a valid AsymmetricEncryption algorithm for {}.",
alg
);
Err(Error::InvalidArgument)
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(asym_encrypt: AsymmetricEncryption) -> Self {
match asym_encrypt {
AsymmetricEncryption::RsaPkcs1v15Crypt => psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_CRYPT,
AsymmetricEncryption::RsaOaep { hash_alg } => unsafe {
psa_crypto_sys::PSA_ALG_RSA_OAEP(hash_alg.into())
},
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(cipher: Cipher) -> Self {
match cipher {
Cipher::StreamCipher => psa_crypto_sys::PSA_ALG_STREAM_CIPHER,
Cipher::Ctr => psa_crypto_sys::PSA_ALG_CTR,
Cipher::Cfb => psa_crypto_sys::PSA_ALG_CFB,
Cipher::Ofb => psa_crypto_sys::PSA_ALG_OFB,
Cipher::Xts => psa_crypto_sys::PSA_ALG_XTS,
Cipher::EcbNoPadding => psa_crypto_sys::PSA_ALG_ECB_NO_PADDING,
Cipher::CbcNoPadding => psa_crypto_sys::PSA_ALG_CBC_NO_PADDING,
Cipher::CbcPkcs7 => psa_crypto_sys::PSA_ALG_CBC_PKCS7,
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for Mac {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if psa_crypto_sys::PSA_ALG_IS_MAC(alg) {
if unsafe { psa_crypto_sys::PSA_ALG_FULL_LENGTH_MAC(alg) } == alg {
Ok(Mac::FullLength(alg.try_into()?))
} else {
let mac_length = unsafe { psa_crypto_sys::PSA_MAC_TRUNCATED_LENGTH(alg) };
let mac_alg: FullLengthMac =
unsafe { psa_crypto_sys::PSA_ALG_FULL_LENGTH_MAC(alg) }.try_into()?;
Ok(Mac::Truncated {
mac_alg,
mac_length,
})
}
} else {
error!("Can not find a valid MAC algorithm for {}.", alg);
Err(Error::InvalidArgument)
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for FullLengthMac {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if psa_crypto_sys::PSA_ALG_IS_HMAC(alg) {
Ok(FullLengthMac::Hmac {
hash_alg: psa_crypto_sys::PSA_ALG_HMAC_GET_HASH(alg).try_into()?,
})
} else if alg == psa_crypto_sys::PSA_ALG_CBC_MAC {
Ok(FullLengthMac::CbcMac)
} else if alg == psa_crypto_sys::PSA_ALG_CMAC {
Ok(FullLengthMac::Cmac)
} else {
error!("Can not find a valid MAC algorithm for {}.", alg);
Err(Error::InvalidArgument)
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(mac: Mac) -> Self {
match mac {
Mac::FullLength(full_length_mac) => full_length_mac.into(),
Mac::Truncated {
mac_alg: alg,
mac_length: length,
// The following call is NOT currently checked. If length is invalid, the return of this call is unspecified
} => unsafe { psa_crypto_sys::PSA_ALG_TRUNCATED_MAC(alg.into(), length) },
}
}
}
impl From for Mac {
fn from(full_length_mac: FullLengthMac) -> Self {
Mac::FullLength(full_length_mac)
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(full_length_mac: FullLengthMac) -> Self {
match full_length_mac {
FullLengthMac::CbcMac => psa_crypto_sys::PSA_ALG_CBC_MAC,
FullLengthMac::Cmac => psa_crypto_sys::PSA_ALG_CMAC,
FullLengthMac::Hmac { hash_alg } => unsafe {
psa_crypto_sys::PSA_ALG_HMAC(hash_alg.into())
},
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for Aead {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if let Ok(aead_with_default_length_tag) = AeadWithDefaultLengthTag::try_from(alg) {
Ok(Aead::AeadWithDefaultLengthTag(aead_with_default_length_tag))
} else {
// Must be shortened tag
let aead_alg = AeadWithDefaultLengthTag::try_from(unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg)
})?;
let tag_length = psa_crypto_sys::PSA_ALG_AEAD_TAG_TRUNCATED_LENGTH(alg);
Ok(Aead::AeadWithShortenedTag {
aead_alg,
tag_length,
})
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for AeadWithDefaultLengthTag {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if alg
== unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_CCM)
}
{
Ok(AeadWithDefaultLengthTag::Ccm)
} else if alg
== unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_GCM)
}
{
Ok(AeadWithDefaultLengthTag::Gcm)
} else if alg
== unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(
psa_crypto_sys::PSA_ALG_CHACHA20_POLY1305,
)
}
{
Ok(AeadWithDefaultLengthTag::Chacha20Poly1305)
} else {
error!("Can not find a valid Aead algorithm for {}.", alg);
Err(Error::InvalidArgument)
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(aead: Aead) -> Self {
match aead {
Aead::AeadWithDefaultLengthTag(aead_with_default_length_mac) => {
aead_with_default_length_mac.into()
}
// The following call is NOT currently checked. If length is invalid, the return of this call is unspecified
Aead::AeadWithShortenedTag {
aead_alg,
tag_length,
} => unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_SHORTENED_TAG(aead_alg.into(), tag_length)
},
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(aead_with_default_length_tag: AeadWithDefaultLengthTag) -> Self {
match aead_with_default_length_tag {
AeadWithDefaultLengthTag::Ccm => unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_CCM)
},
AeadWithDefaultLengthTag::Gcm => unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_GCM)
},
AeadWithDefaultLengthTag::Chacha20Poly1305 => unsafe {
psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(
psa_crypto_sys::PSA_ALG_CHACHA20_POLY1305,
)
},
}
}
}
impl From for Aead {
fn from(aead_with_default_tag_length: AeadWithDefaultLengthTag) -> Self {
Aead::AeadWithDefaultLengthTag(aead_with_default_tag_length)
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(key_agreement: KeyAgreement) -> Self {
match key_agreement {
KeyAgreement::Raw(raw_key_agreement) => raw_key_agreement.into(),
KeyAgreement::WithKeyDerivation { ka_alg, kdf_alg } => unsafe {
psa_crypto_sys::PSA_ALG_KEY_AGREEMENT(ka_alg.into(), kdf_alg.into())
},
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for KeyAgreement {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if psa_crypto_sys::PSA_ALG_IS_KEY_AGREEMENT(alg) {
if psa_crypto_sys::PSA_ALG_IS_RAW_KEY_AGREEMENT(alg) {
Ok(KeyAgreement::Raw(alg.try_into()?))
} else {
Ok(KeyAgreement::WithKeyDerivation {
ka_alg: unsafe { psa_crypto_sys::PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) }
.try_into()?,
kdf_alg: unsafe { psa_crypto_sys::PSA_ALG_KEY_AGREEMENT_GET_KDF(alg) }
.try_into()?,
})
}
} else {
error!("Can not find a valid KeyAgreement algorithm for {}.", alg);
Err(Error::InvalidArgument)
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for RawKeyAgreement {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if psa_crypto_sys::PSA_ALG_IS_FFDH(alg) {
Ok(RawKeyAgreement::Ffdh)
} else if psa_crypto_sys::PSA_ALG_IS_ECDH(alg) {
Ok(RawKeyAgreement::Ecdh)
} else {
error!(
"Can not find a valid RawKeyAgreement algorithm for {}.",
alg
);
Err(Error::InvalidArgument)
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(raw_key_agreement: RawKeyAgreement) -> Self {
match raw_key_agreement {
RawKeyAgreement::Ecdh => psa_crypto_sys::PSA_ALG_ECDH,
RawKeyAgreement::Ffdh => psa_crypto_sys::PSA_ALG_FFDH,
}
}
}
impl From for KeyAgreement {
fn from(raw_key_agreement: RawKeyAgreement) -> Self {
KeyAgreement::Raw(raw_key_agreement)
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_algorithm_t {
fn from(key_derivation: KeyDerivation) -> Self {
match key_derivation {
KeyDerivation::Hkdf { hash_alg, .. } => unsafe {
psa_crypto_sys::PSA_ALG_HKDF(hash_alg.into())
},
KeyDerivation::Tls12Prf { hash_alg, .. } => unsafe {
psa_crypto_sys::PSA_ALG_TLS12_PRF(hash_alg.into())
},
KeyDerivation::Tls12PskToMs { hash_alg, .. } => unsafe {
psa_crypto_sys::PSA_ALG_TLS12_PSK_TO_MS(hash_alg.into())
},
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for KeyDerivation {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result {
if psa_crypto_sys::PSA_ALG_IS_HKDF(alg) {
Ok(KeyDerivation::Hkdf {
hash_alg: psa_crypto_sys::PSA_ALG_HKDF_GET_HASH(alg).try_into()?,
})
} else if psa_crypto_sys::PSA_ALG_IS_TLS12_PRF(alg) {
Ok(KeyDerivation::Tls12Prf {
hash_alg: psa_crypto_sys::PSA_ALG_TLS12_PRF_GET_HASH(alg).try_into()?,
})
} else if psa_crypto_sys::PSA_ALG_IS_TLS12_PSK_TO_MS(alg) {
Ok(KeyDerivation::Tls12PskToMs {
hash_alg: psa_crypto_sys::PSA_ALG_TLS12_PSK_TO_MS_GET_HASH(alg).try_into()?,
})
} else {
error!("Can not find a valid KeyDerivation algorithm for {}.", alg);
Err(Error::InvalidArgument)
}
}
}
#[cfg(test)]
mod test {
use crate::types::algorithm::{Algorithm, AsymmetricSignature, Hash, SignHash};
use core::convert::{TryFrom, TryInto};
#[test]
fn conversion() {
assert_eq!(
Hash::Sha256,
psa_crypto_sys::PSA_ALG_SHA_256.try_into().unwrap()
);
assert_eq!(psa_crypto_sys::PSA_ALG_SHA_256, Hash::Sha256.into());
assert_eq!(
SignHash::Any,
psa_crypto_sys::PSA_ALG_ANY_HASH.try_into().unwrap()
);
assert_eq!(
SignHash::Specific(Hash::Sha256),
psa_crypto_sys::PSA_ALG_SHA_256.try_into().unwrap()
);
assert_eq!(
Algorithm::AsymmetricSignature(AsymmetricSignature::Ecdsa {
hash_alg: SignHash::Specific(Hash::Sha3_512),
}),
psa_crypto_sys::PSA_ALG_ECDSA(psa_crypto_sys::PSA_ALG_SHA3_512)
.try_into()
.unwrap()
);
assert_eq!(
psa_crypto_sys::PSA_ALG_ECDSA(psa_crypto_sys::PSA_ALG_SHA3_512),
Algorithm::AsymmetricSignature(AsymmetricSignature::Ecdsa {
hash_alg: SignHash::Specific(Hash::Sha3_512),
})
.try_into()
.unwrap()
);
}
#[test]
fn convert_fail() {
let _ = AsymmetricSignature::try_from(0xDEAD_BEEF).unwrap_err();
let _ = AsymmetricSignature::try_from(psa_crypto_sys::PSA_ALG_ANY_HASH).unwrap_err();
let _ = Hash::try_from(psa_crypto_sys::PSA_ALG_ANY_HASH).unwrap_err();
let _ = Hash::try_from(psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN_RAW).unwrap_err();
}
}
psa-crypto-0.9.2/src/types/key.rs 0000644 0000000 0000000 00000166537 10461020230 0015050 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PSA Key types
#![allow(deprecated)]
#[cfg(feature = "operations")]
use crate::initialized;
#[cfg(feature = "interface")]
use crate::types::algorithm::{Aead, AsymmetricEncryption, AsymmetricSignature, Mac};
use crate::types::algorithm::{Algorithm, Cipher, KeyAgreement, RawKeyAgreement};
#[cfg(feature = "operations")]
use crate::types::status::Status;
use crate::types::status::{Error, Result};
#[cfg(feature = "interface")]
use core::convert::{TryFrom, TryInto};
use core::fmt;
use log::error;
pub use psa_crypto_sys::{self, psa_key_id_t, PSA_KEY_ID_USER_MAX, PSA_KEY_ID_USER_MIN};
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
/// Native definition of the attributes needed to fully describe
/// a cryptographic key.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub struct Attributes {
/// Lifetime of the key
pub lifetime: Lifetime,
/// Intrinsic category and type of the key
pub key_type: Type,
/// Size of the key in bits
pub bits: usize,
/// Policy restricting the permitted usage of the key
pub policy: Policy,
}
impl Attributes {
/// Check if a key has permission to be exported
pub fn is_exportable(self) -> bool {
self.policy.usage_flags.export
}
/// Check export in a fallible way
///
/// # Example
///
/// ```
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{Algorithm, AsymmetricSignature, Hash};
///
/// let mut usage_flags: UsageFlags = Default::default();
/// let mut attributes = Attributes {
/// key_type: Type::RsaKeyPair,
/// bits: 1024,
/// lifetime: Lifetime::Volatile,
/// policy: Policy {
/// usage_flags,
/// permitted_algorithms: Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
/// hash_alg: Hash::Sha256.into(),
/// }),
/// },
/// };
/// // Can not export because the export flag is set to false.
/// attributes.can_export().unwrap_err();
/// ```
pub fn can_export(self) -> Result<()> {
if self.is_exportable() {
Ok(())
} else {
error!("Key attributes do not permit exporting key.");
Err(Error::NotPermitted)
}
}
/// Check if a key has permission to sign a message hash
pub fn is_hash_signable(self) -> bool {
self.policy.usage_flags.sign_hash
}
/// Check hash signing permission in a fallible way
pub fn can_sign_hash(self) -> Result<()> {
if self.is_hash_signable() {
Ok(())
} else {
error!("Key attributes do not permit signing hashes.");
Err(Error::NotPermitted)
}
}
/// Check if a key has permission to verify a message hash
pub fn is_hash_verifiable(self) -> bool {
self.policy.usage_flags.verify_hash
}
/// Check hash verifying permission in a fallible way
pub fn can_verify_hash(self) -> Result<()> {
if self.is_hash_verifiable() {
Ok(())
} else {
error!("Key attributes do not permit verifying hashes.");
Err(Error::NotPermitted)
}
}
/// Check if a key has permission to sign a message
pub fn is_message_signable(self) -> bool {
self.policy.usage_flags.sign_hash | self.policy.usage_flags.sign_message
}
/// Check message signing permission in a fallible way
pub fn can_sign_message(self) -> Result<()> {
if self.is_message_signable() {
Ok(())
} else {
error!("Key attributes do not permit signing messages.");
Err(Error::NotPermitted)
}
}
/// Check if a key has permission to verify a message
pub fn is_message_verifiable(self) -> bool {
self.policy.usage_flags.verify_hash | self.policy.usage_flags.verify_message
}
/// Check message verifying permission in a fallible way
pub fn can_verify_message(self) -> Result<()> {
if self.is_message_verifiable() {
Ok(())
} else {
error!("Key attributes do not permit verifying messages.");
Err(Error::NotPermitted)
}
}
/// Check if a key has permissions to encrypt a message
pub fn is_encrypt_permitted(self) -> bool {
self.policy.usage_flags.encrypt
}
/// Check encrypt permission in a fallible way
pub fn can_encrypt_message(self) -> Result<()> {
if self.is_encrypt_permitted() {
Ok(())
} else {
error!("Key attributes do not permit encrypting messages.");
Err(Error::NotPermitted)
}
}
/// Check if a key has permissions to decrypt a message
pub fn is_decrypt_permitted(self) -> bool {
self.policy.usage_flags.decrypt
}
/// Check decrypt permission in a fallible way
pub fn can_decrypt_message(self) -> Result<()> {
if self.is_decrypt_permitted() {
Ok(())
} else {
error!("Key attributes do not permit decrypting messages.");
Err(Error::NotPermitted)
}
}
/// Check if a key has permissions to be derived from
pub fn is_derivable(self) -> bool {
self.policy.usage_flags.derive
}
/// Check derive permission of a fallible way
pub fn can_derive_from(self) -> Result<()> {
if self.is_derivable() {
Ok(())
} else {
error!("Key attributes do not permit derivation.");
Err(Error::NotPermitted)
}
}
/// Check if can be converted into psa_key_attributes_t
#[cfg(feature = "interface")]
pub fn can_convert_into_psa(self) -> Result<()> {
let _ = psa_crypto_sys::psa_key_attributes_t::try_from(self)?;
Ok(())
}
/// Check if the alg given for a cryptographic operation is permitted to be used with the key
pub fn is_alg_permitted(self, alg: Algorithm) -> bool {
match self.policy.permitted_algorithms {
Algorithm::None => false,
Algorithm::AsymmetricSignature(asymmetric_signature_alg_policy) => {
if let Algorithm::AsymmetricSignature(asymmetric_signature_alg) = alg {
asymmetric_signature_alg_policy.is_alg_permitted(asymmetric_signature_alg)
} else {
false
}
}
// These ones can not be wildcard algorithms: it is sufficient to just check for
// equality.
permitted_alg => permitted_alg == alg,
}
}
/// Check if alg is permitted in a fallible way
pub fn permits_alg(self, alg: Algorithm) -> Result<()> {
if self.is_alg_permitted(alg) {
Ok(())
} else {
error!("Key attributes do not permit specified algorithm.");
Err(Error::NotPermitted)
}
}
/// Check if the alg given for a cryptographic operation is compatible with the type of the
/// key
///
/// # Example
///
/// ```
/// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// use psa_crypto::types::algorithm::{Algorithm, AsymmetricSignature, Hash};
///
/// let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
/// hash_alg: Hash::Sha256.into(),
/// });
/// let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
/// hash_alg: Hash::Sha256.into(),
/// });
/// let mut usage_flags: UsageFlags = Default::default();
/// let mut attributes = Attributes {
/// key_type: Type::RsaKeyPair,
/// bits: 1024,
/// lifetime: Lifetime::Volatile,
/// policy: Policy {
/// usage_flags,
/// permitted_algorithms: permitted_alg,
/// },
/// };
/// assert!(attributes.is_compatible_with_alg(alg));
/// attributes.key_type = Type::RsaPublicKey;
/// assert!(attributes.is_compatible_with_alg(alg));
/// ```
pub fn is_compatible_with_alg(self, alg: Algorithm) -> bool {
match self.key_type {
Type::RawData => false,
Type::Hmac => alg.is_hmac(),
Type::Derive => matches!(alg, Algorithm::KeyDerivation(_)),
Type::Aes | Type::Camellia => {
if let Algorithm::Mac(mac_alg) = alg {
mac_alg.is_block_cipher_needed()
} else if let Algorithm::Cipher(cipher_alg) = alg {
cipher_alg.is_block_cipher_mode()
} else if let Algorithm::Aead(aead_alg) = alg {
aead_alg.is_aead_on_block_cipher()
} else {
false
}
}
Type::Des => {
if let Algorithm::Mac(mac_alg) = alg {
mac_alg.is_block_cipher_needed()
} else if let Algorithm::Cipher(cipher_alg) = alg {
cipher_alg.is_block_cipher_mode()
} else {
false
}
}
Type::Arc4 => alg == Algorithm::Cipher(Cipher::StreamCipher),
Type::Chacha20 => {
if alg == Algorithm::Cipher(Cipher::StreamCipher) {
true
} else if let Algorithm::Aead(aead_alg) = alg {
aead_alg.is_chacha20_poly1305_alg()
} else {
false
}
}
Type::RsaPublicKey | Type::RsaKeyPair => {
if let Algorithm::AsymmetricSignature(sign_alg) = alg {
sign_alg.is_rsa_alg()
} else {
matches!(alg, Algorithm::AsymmetricEncryption(_))
}
}
Type::EccKeyPair { .. } | Type::EccPublicKey { .. } => match alg {
Algorithm::KeyAgreement(KeyAgreement::Raw(RawKeyAgreement::Ecdh))
| Algorithm::KeyAgreement(KeyAgreement::WithKeyDerivation {
ka_alg: RawKeyAgreement::Ecdh,
..
}) => true,
Algorithm::AsymmetricSignature(sign_alg) => sign_alg.is_ecc_alg(),
_ => false,
},
Type::DhKeyPair { .. } | Type::DhPublicKey { .. } => matches!(
alg,
Algorithm::KeyAgreement(KeyAgreement::Raw(RawKeyAgreement::Ffdh))
| Algorithm::KeyAgreement(KeyAgreement::WithKeyDerivation {
ka_alg: RawKeyAgreement::Ffdh,
..
})
),
}
}
/// Check if alg is compatible in a fallible way
pub fn compatible_with_alg(self, alg: Algorithm) -> Result<()> {
if self.is_compatible_with_alg(alg) {
Ok(())
} else {
error!("Key attributes are not compatible with specified algorithm.");
Err(Error::NotPermitted)
}
}
#[cfg(feature = "operations")]
pub(crate) fn reset(attributes: &mut psa_crypto_sys::psa_key_attributes_t) {
unsafe { psa_crypto_sys::psa_reset_key_attributes(attributes) };
}
/// Gets the attributes for a given key ID
///
/// The `Id` structure can be created with the `from_persistent_key_id` constructor on `Id`.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::key_management;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # use psa_crypto::types::algorithm::{AsymmetricSignature, Hash};
/// # let mut usage_flags: UsageFlags = Default::default();
/// # usage_flags.set_sign_hash().set_verify_hash();
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags,
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
/// psa_crypto::init().unwrap();
/// let my_key_id = key_management::generate(attributes, None).unwrap();
/// //...
/// let key_attributes = Attributes::from_key_id(my_key_id);
/// ```
#[cfg(feature = "operations")]
pub fn from_key_id(key_id: Id) -> Result {
initialized()?;
let mut key_attributes = unsafe { psa_crypto_sys::psa_key_attributes_init() };
Status::from(unsafe {
psa_crypto_sys::psa_get_key_attributes(key_id.0, &mut key_attributes)
})
.to_result()?;
let attributes = Attributes::try_from(key_attributes);
Attributes::reset(&mut key_attributes);
attributes
}
/// Sufficient size for a buffer to export the key, if supported
#[cfg(feature = "interface")]
pub fn export_key_output_size(self) -> Result {
Attributes::export_key_output_size_base(self.key_type, self.bits)
}
/// Sufficient size for a buffer to export the public key, if supported
#[cfg(feature = "interface")]
pub fn export_public_key_output_size(self) -> Result {
match self.key_type {
Type::RsaKeyPair
| Type::RsaPublicKey
| Type::EccKeyPair { .. }
| Type::EccPublicKey { .. }
| Type::DhKeyPair { .. }
| Type::DhPublicKey { .. } => {
let pub_type = self.key_type.key_type_public_key_of_key_pair()?;
Attributes::export_key_output_size_base(pub_type, self.bits)
}
_ => Err(Error::InvalidArgument),
}
}
/// Sufficient size for a buffer to export the given key type, if supported
#[cfg(feature = "interface")]
fn export_key_output_size_base(key_type: Type, bits: usize) -> Result {
match unsafe { psa_crypto_sys::PSA_EXPORT_KEY_OUTPUT_SIZE(key_type.try_into()?, bits) } {
0 => Err(Error::NotSupported),
size => Ok(size),
}
}
/// Sufficient buffer size for a signature using the given key, if the key is supported
#[cfg(feature = "interface")]
pub fn sign_output_size(self, alg: AsymmetricSignature) -> Result {
self.compatible_with_alg(alg.into())?;
Ok(unsafe {
psa_crypto_sys::PSA_SIGN_OUTPUT_SIZE(self.key_type.try_into()?, self.bits, alg.into())
})
}
/// Sufficient buffer size for an encrypted message using the given asymmetric encryption algorithm
#[cfg(feature = "interface")]
pub fn asymmetric_encrypt_output_size(self, alg: AsymmetricEncryption) -> Result {
self.compatible_with_alg(alg.into())?;
Ok(unsafe {
psa_crypto_sys::PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
self.key_type.try_into()?,
self.bits,
alg.into(),
)
})
}
/// Sufficient buffer size for a decrypted message using the given asymmetric encryption algorithm
#[cfg(feature = "interface")]
pub fn asymmetric_decrypt_output_size(self, alg: AsymmetricEncryption) -> Result {
self.compatible_with_alg(alg.into())?;
Ok(unsafe {
psa_crypto_sys::PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
self.key_type.try_into()?,
self.bits,
alg.into(),
)
})
}
/// Sufficient buffer size for the MAC of the specified algorithm, if compatible
#[cfg(feature = "interface")]
pub fn mac_length(self, mac_alg: Mac) -> Result {
self.compatible_with_alg(mac_alg.into())?;
Ok(unsafe {
psa_crypto_sys::PSA_MAC_LENGTH(self.key_type.try_into()?, self.bits, mac_alg.into())
})
}
/// Sufficient buffer size for an encrypted message using the given aead algorithm
#[cfg(feature = "interface")]
pub fn aead_encrypt_output_size(self, alg: Aead, plaintext_len: usize) -> Result {
self.compatible_with_alg(alg.into())?;
Ok(unsafe {
psa_crypto_sys::PSA_AEAD_ENCRYPT_OUTPUT_SIZE(
self.key_type.try_into()?,
alg.into(),
plaintext_len,
)
})
}
/// Sufficient buffer size for an encrypted message using the given aead algorithm
#[cfg(feature = "interface")]
pub fn aead_decrypt_output_size(self, alg: Aead, ciphertext_len: usize) -> Result {
self.compatible_with_alg(alg.into())?;
Ok(unsafe {
psa_crypto_sys::PSA_AEAD_DECRYPT_OUTPUT_SIZE(
self.key_type.try_into()?,
alg.into(),
ciphertext_len,
)
})
}
/// The length of a tag for an AEAD algorithm
#[cfg(feature = "interface")]
pub fn aead_tag_length(self, alg: Aead) -> Result {
self.compatible_with_alg(alg.into())?;
Ok(psa_crypto_sys::PSA_AEAD_TAG_LENGTH(
self.key_type.try_into()?,
self.bits,
alg.into(),
))
}
/// Sufficient buffer size for the resulting shared secret from a raw key agreement
#[cfg(feature = "interface")]
pub fn raw_key_agreement_output_size(self, alg: RawKeyAgreement) -> Result {
if alg == RawKeyAgreement::Ffdh {
return Err(Error::NotSupported);
}
self.compatible_with_alg(KeyAgreement::Raw(alg).into())?;
Ok(unsafe {
psa_crypto_sys::PSA_RAW_ECDH_KEY_AGREEMENT_OUTPUT_SIZE(
self.key_type.try_into()?,
self.bits,
)
})
}
}
/// The lifetime of a key indicates where it is stored and which application and system actions
/// will create and destroy it.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum Lifetime {
/// A volatile key only exists as long as the identifier to it is not destroyed.
Volatile,
/// A persistent key remains in storage until it is explicitly destroyed or until the
/// corresponding storage area is wiped.
Persistent,
/// Implementations can offer other storage areas designated by other lifetime values as
/// implementation-specific extensions.
Custom(u32),
}
/// Enumeration of key types supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum Type {
/// Not a valid key type for any cryptographic operation but can be used to store arbitrary
/// data in the key store.
RawData,
/// HMAC key.
Hmac,
/// A secret key for derivation.
Derive,
/// Key for a cipher, AEAD or MAC algorithm based on the AES block cipher.
Aes,
/// Key for a cipher or MAC algorithm based on DES or 3DES (Triple-DES).
Des,
/// Key for a cipher, AEAD or MAC algorithm based on the Camellia block cipher.
Camellia,
/// Key for the RC4 stream cipher.
Arc4,
/// Key for the ChaCha20 stream cipher or the Chacha20-Poly1305 AEAD algorithm.
Chacha20,
/// RSA public key.
RsaPublicKey,
/// RSA key pair: both the private and public key.
RsaKeyPair,
/// Elliptic curve key pair: both the private and public key.
EccKeyPair {
/// ECC curve family to use.
curve_family: EccFamily,
},
/// Elliptic curve public key.
EccPublicKey {
/// ECC curve family to use.
curve_family: EccFamily,
},
/// Diffie-Hellman key pair: both the private key and public key.
DhKeyPair {
/// Diffie-Hellman group family to use.
group_family: DhFamily,
},
/// Diffie-Hellman public key.
DhPublicKey {
/// Diffie-Hellman group family to use.
group_family: DhFamily,
},
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::RawData => write!(f, "Raw data"),
Type::Hmac => write!(f, "HMAC key"),
Type::Derive => write!(f, "Derivation key"),
Type::Aes => write!(f, "Key for an algorithm based on AES"),
Type::Des => write!(f, "Key for an algorithm based on DES or 3DES"),
Type::Camellia => write!(f, "Key for an algorithm based on Camellia"),
Type::Arc4 => write!(f, "Key for the RC4 stream cipher"),
Type::Chacha20 => write!(f, "Key for an algorithm based on ChaCha20"),
Type::RsaPublicKey => write!(f, "RSA public key"),
Type::RsaKeyPair => write!(f, "RSA key pair"),
Type::EccKeyPair { curve_family } => write!(f, "ECC key pair (using {})", curve_family),
Type::EccPublicKey { curve_family } => {
write!(f, "ECC public key (using {})", curve_family)
}
Type::DhKeyPair { group_family } => {
write!(f, "Diffie-Hellman key pair (using {})", group_family)
}
Type::DhPublicKey { group_family } => {
write!(f, "Diffie-Hellman public key (using {})", group_family)
}
}
}
}
impl Type {
/// Checks if a key type is ECC key pair with any curve family inside.
pub fn is_ecc_key_pair(self) -> bool {
matches!(self, Type::EccKeyPair { .. })
}
/// Checks if a key type is ECC public key with any curve family inside.
///
/// # Example
///
/// ```
/// use psa_crypto::types::key::{Type, EccFamily};
///
/// assert!(Type::EccPublicKey { curve_family: EccFamily::SecpK1}.is_ecc_public_key());
/// ```
pub fn is_ecc_public_key(self) -> bool {
matches!(self, Type::EccPublicKey { .. })
}
/// Checks if a key type is RSA public key.
pub fn is_rsa_public_key(self) -> bool {
matches!(self, Type::RsaPublicKey)
}
/// Checks if a key type is DH public key with any group family inside.
pub fn is_dh_public_key(self) -> bool {
matches!(self, Type::DhPublicKey { .. })
}
/// Checks if a key type is DH key pair with any group family inside.
pub fn is_dh_key_pair(self) -> bool {
matches!(self, Type::DhKeyPair { .. })
}
/// Checks if a key type is an asymmetric public key type.
pub fn is_public_key(self) -> bool {
self.is_rsa_public_key() || self.is_ecc_public_key() || self.is_dh_public_key()
}
/// If key is public or key pair, returns the corresponding public key type.
#[cfg(feature = "interface")]
pub fn key_type_public_key_of_key_pair(self) -> Result {
match self {
Type::RsaKeyPair
| Type::RsaPublicKey
| Type::EccKeyPair { .. }
| Type::EccPublicKey { .. }
| Type::DhKeyPair { .. }
| Type::DhPublicKey { .. } => {
Ok(
unsafe {
psa_crypto_sys::PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(self.try_into()?)
}
.try_into()?,
)
}
_ => Err(Error::InvalidArgument),
}
}
}
/// Enumeration of elliptic curve families supported. They are needed to create an ECC key.
/// The specific curve used for each family is given by the `bits` field of the key attributes.
/// See the book for more details.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum EccFamily {
/// SEC Koblitz curves over prime fields.
/// This family comprises the following curves:
/// * secp192k1: `bits` = 192
/// * secp224k1: `bits` = 225
/// * secp256k1: `bits` = 256
SecpK1,
/// SEC random curves over prime fields.
/// This family comprises the following curves:
/// * secp192r1: `bits` = 192
/// * secp224r1: `bits` = 224
/// * secp256r1: `bits` = 256
/// * secp384r1: `bits` = 384
/// * secp521r1: `bits` = 512
SecpR1,
/// SEC additional random curves over prime fields.
/// This family comprises the following curves:
/// * secp160r2: `bits` = 160 (Deprecated)
#[deprecated = "This family of curve is weak and deprecated."]
SecpR2,
/// SEC Koblitz curves over binary fields.
/// This family comprises the following curves:
/// * sect163k1: `bits` = 163 (DEPRECATED)
/// * sect233k1: `bits` = 233
/// * sect239k1: `bits` = 239
/// * sect283k1: `bits` = 283
/// * sect409k1: `bits` = 409
/// * sect571k1: `bits` = 571
SectK1,
/// SEC random curves over binary fields.
/// This family comprises the following curves:
/// * sect163r1: `bits` = 163 (DEPRECATED)
/// * sect233r1: `bits` = 233
/// * sect283r1: `bits` = 283
/// * sect409r1: `bits` = 409
/// * sect571r1: `bits` = 571
SectR1,
/// SEC additional random curves over binary fields.
/// This family comprises the following curves:
/// * sect163r2 : bits = 163 (DEPRECATED)
#[deprecated = "This family of curve is weak and deprecated."]
SectR2,
/// Brainpool P random curves.
/// This family comprises the following curves:
/// * brainpoolP160r1: `bits` = 160 (DEPRECATED)
/// * brainpoolP192r1: `bits` = 192
/// * brainpoolP224r1: `bits` = 224
/// * brainpoolP256r1: `bits` = 256
/// * brainpoolP320r1: `bits` = 320
/// * brainpoolP384r1: `bits` = 384
/// * brainpoolP512r1: `bits` = 512
BrainpoolPR1,
/// Curve used primarily in France and elsewhere in Europe.
/// This family comprises one 256-bit curve:
/// * FRP256v1: `bits` = 256
Frp,
/// Montgomery curves.
/// This family comprises the following Montgomery curves:
/// * Curve25519: `bits` = 255
/// * Curve448: `bits` = 448
Montgomery,
}
impl fmt::Display for EccFamily {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EccFamily::SecpK1 => write!(f, "SEC Koblitz curves over prime fields"),
EccFamily::SecpR1 => write!(f, "SEC random curves over prime fields"),
EccFamily::SecpR2 => write!(f, "SEC additional random curves over prime fields"),
EccFamily::SectK1 => write!(f, "SEC Koblitz curves over binary fields"),
EccFamily::SectR1 => write!(f, "SEC random curves over binary fields"),
EccFamily::SectR2 => write!(f, "SEC additional random curves over binary fields"),
EccFamily::BrainpoolPR1 => write!(f, "Brainpool P random curves"),
EccFamily::Frp => write!(f, "FRP curve"),
EccFamily::Montgomery => write!(f, "Montgomery curve"),
}
}
}
/// Enumeration of Diffie Hellman group families supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub enum DhFamily {
/// Diffie-Hellman groups defined in RFC 7919 Appendix A.
/// This family includes groups with the following `bits`: 2048, 3072, 4096, 6144, 8192.
/// An implementation can support all of these sizes or only a subset.
Rfc7919,
}
impl fmt::Display for DhFamily {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DhFamily::Rfc7919 => write!(f, "Diffie-Hellman groups defined in RFC 7919 Appendix A"),
}
}
}
/// Definition of the key policy, what is permitted to do with the key.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub struct Policy {
/// Usage flags for the key.
pub usage_flags: UsageFlags,
/// Permitted algorithms to be used with the key.
pub permitted_algorithms: Algorithm,
}
/// Definition of the usage flags. They encode what kind of operations are permitted on the key.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub struct UsageFlags {
/// Permission to export the key.
export: bool,
/// Permission to copy the key.
copy: bool,
/// Permission for the implementation to cache the key.
cache: bool,
/// Permission to encrypt a message with the key.
encrypt: bool,
/// Permission to decrypt a message with the key.
decrypt: bool,
/// Permission to sign a message with the key.
sign_message: bool,
/// Permission to verify a message signature with the key.
verify_message: bool,
/// Permission to sign a message hash with the key.
sign_hash: bool,
/// Permission to verify a message hash with the key.
verify_hash: bool,
/// Permission to derive other keys from this key.
derive: bool,
}
impl UsageFlags {
///Setter for the export flag
pub fn set_export(&mut self) -> &mut Self {
self.export = true;
self
}
///Getter for the export flag
pub fn export(&self) -> bool {
self.export
}
///Setter for the copy flag
pub fn set_copy(&mut self) -> &mut Self {
self.copy = true;
self
}
///Getter for the copy flag
pub fn copy(&self) -> bool {
self.copy
}
///Setter for the cache flag
pub fn set_cache(&mut self) -> &mut Self {
self.cache = true;
self
}
///Getter for the cache flag
pub fn cache(&self) -> bool {
self.cache
}
///Setter for the encrypt flag
pub fn set_encrypt(&mut self) -> &mut Self {
self.encrypt = true;
self
}
///Getter for the encrypt flag
pub fn encrypt(&self) -> bool {
self.encrypt
}
///Setter for the decrypt flag
pub fn set_decrypt(&mut self) -> &mut Self {
self.decrypt = true;
self
}
///Getter for the decrypt flag
pub fn decrypt(&self) -> bool {
self.decrypt
}
///Setter for the sign_hash flag (also sets the sign_message flag)
pub fn set_sign_hash(&mut self) -> &mut Self {
self.sign_hash = true;
self.sign_message = true;
self
}
///Getter for the sign_hash flag
pub fn sign_hash(&self) -> bool {
self.sign_hash
}
///Setter for the sign_message flag
pub fn set_sign_message(&mut self) -> &mut Self {
self.sign_message = true;
self
}
///Getter for the sign_message flag
pub fn sign_message(&self) -> bool {
self.sign_message
}
///Setter for the verify_hash flag (also sets the varify_message flag)
pub fn set_verify_hash(&mut self) -> &mut Self {
self.verify_hash = true;
self.verify_message = true;
self
}
///Getter for the verify_hash flag
pub fn verify_hash(&self) -> bool {
self.verify_hash
}
///Setter for the verify_message flag
pub fn set_verify_message(&mut self) -> &mut Self {
self.verify_message = true;
self
}
///Getter for the verify_message flag
pub fn verify_message(&self) -> bool {
self.verify_message
}
///Setter for the derive flag
pub fn set_derive(&mut self) -> &mut Self {
self.derive = true;
self
}
///Getter for the derive flag
pub fn derive(&self) -> bool {
self.derive
}
}
/// Definition of the key ID.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
pub struct Id(pub(crate) psa_key_id_t);
impl Id {
/// Create a new Id from a persistent key ID
#[cfg(feature = "operations")]
pub fn from_persistent_key_id(id: u32) -> Result {
// Checking if the id is one of a persistent key that exists by fetching its attributes.
let _ = Attributes::from_key_id(Id(id))?;
Ok(Id(id))
}
}
#[cfg(feature = "interface")]
impl TryFrom for psa_crypto_sys::psa_key_attributes_t {
type Error = Error;
fn try_from(attributes: Attributes) -> Result {
let mut attrs = unsafe { psa_crypto_sys::psa_key_attributes_init() };
unsafe { psa_crypto_sys::psa_set_key_lifetime(&mut attrs, attributes.lifetime.into()) };
unsafe {
psa_crypto_sys::psa_set_key_usage_flags(
&mut attrs,
attributes.policy.usage_flags.into(),
)
};
unsafe {
psa_crypto_sys::psa_set_key_algorithm(
&mut attrs,
attributes.policy.permitted_algorithms.try_into()?,
)
};
unsafe { psa_crypto_sys::psa_set_key_type(&mut attrs, attributes.key_type.try_into()?) };
unsafe { psa_crypto_sys::psa_set_key_bits(&mut attrs, attributes.try_into()?) };
Ok(attrs)
}
}
#[cfg(feature = "interface")]
impl TryFrom for usize {
type Error = Error;
// Check if key size is correct for the key type
fn try_from(attributes: Attributes) -> Result {
// For some operations like import 0 size is permitted
if attributes.bits == 0 {
return Ok(attributes.bits);
}
match attributes.key_type {
Type::EccKeyPair { curve_family } | Type::EccPublicKey { curve_family } => {
match curve_family {
// SEC random curves over prime fields.
EccFamily::SecpR1 => match attributes.bits {
192 | 224 | 256 | 284 | 521 => Ok(attributes.bits),
_ => {
error!("Requested key size is not supported ({})", attributes.bits);
Err(Error::InvalidArgument)
}
},
// SEC Koblitz curves over prime fields.
EccFamily::SecpK1 => match attributes.bits {
192 | 224 | 256 => Ok(attributes.bits),
_ => {
error!("Requested key size is not supported ({})", attributes.bits);
Err(Error::InvalidArgument)
}
},
// SEC Koblitz curves over binary fields
EccFamily::SectK1 => match attributes.bits {
233 | 239 | 283 | 409 | 571 => Ok(attributes.bits),
_ => {
error!("Requested key size is not supported ({})", attributes.bits);
Err(Error::InvalidArgument)
}
},
// SEC random curves over binary fields
EccFamily::SectR1 => match attributes.bits {
233 | 283 | 409 | 571 => Ok(attributes.bits),
_ => {
error!("Requested key size is not supported ({})", attributes.bits);
Err(Error::InvalidArgument)
}
},
// Brainpool P random curves
EccFamily::BrainpoolPR1 => match attributes.bits {
192 | 224 | 256 | 320 | 384 | 512 => Ok(attributes.bits),
_ => {
error!("Requested key size is not supported ({})", attributes.bits);
Err(Error::InvalidArgument)
}
},
// Curve used primarily in France and elsewhere in Europe.
EccFamily::Frp => match attributes.bits {
256 => Ok(attributes.bits),
_ => {
error!("Requested key size is not supported ({})", attributes.bits);
Err(Error::InvalidArgument)
}
},
// Montgomery curves
EccFamily::Montgomery => match attributes.bits {
255 | 448 => Ok(attributes.bits),
_ => {
error!("Requested key size is not supported ({})", attributes.bits);
Err(Error::InvalidArgument)
}
},
_ => {
// We don't (yet?) implement checks for other curve families
Ok(attributes.bits)
}
}
}
_ => {
// TO-DO We don't (yet?) implement checks for other types
Ok(attributes.bits)
}
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for Attributes {
type Error = Error;
fn try_from(attributes: psa_crypto_sys::psa_key_attributes_t) -> Result {
Ok(Attributes {
lifetime: unsafe { psa_crypto_sys::psa_get_key_lifetime(&attributes).into() },
key_type: unsafe { psa_crypto_sys::psa_get_key_type(&attributes).try_into()? },
bits: unsafe { psa_crypto_sys::psa_get_key_bits(&attributes) },
policy: Policy {
usage_flags: unsafe { psa_crypto_sys::psa_get_key_usage_flags(&attributes).into() },
permitted_algorithms: unsafe {
psa_crypto_sys::psa_get_key_algorithm(&attributes).try_into()?
},
},
})
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_key_lifetime_t {
fn from(lifetime: Lifetime) -> Self {
match lifetime {
Lifetime::Volatile => psa_crypto_sys::PSA_KEY_LIFETIME_VOLATILE,
Lifetime::Persistent => psa_crypto_sys::PSA_KEY_LIFETIME_PERSISTENT,
Lifetime::Custom(value) => value,
}
}
}
#[cfg(feature = "interface")]
impl From for Lifetime {
fn from(lifetime: psa_crypto_sys::psa_key_lifetime_t) -> Self {
match lifetime {
psa_crypto_sys::PSA_KEY_LIFETIME_VOLATILE => Lifetime::Volatile,
psa_crypto_sys::PSA_KEY_LIFETIME_PERSISTENT => Lifetime::Persistent,
value => Lifetime::Custom(value),
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_key_usage_t {
fn from(flags: UsageFlags) -> Self {
let mut usage_flags = 0;
if flags.export {
usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_EXPORT;
}
if flags.encrypt {
usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_ENCRYPT;
}
if flags.decrypt {
usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_DECRYPT;
}
//TODO: not yet implemented in Mbed Crypto, uncomment when added
//if flags.sign_message {
// usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_SIGN_MESSAGE;
//}
if flags.sign_hash {
usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_SIGN_HASH;
}
//if flags.verify_message {
// usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_VERIFY_MESSAGE;
//}
if flags.verify_hash {
usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_VERIFY_HASH;
}
if flags.derive {
usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_DERIVE;
}
if flags.copy {
usage_flags |= psa_crypto_sys::PSA_KEY_USAGE_COPY;
}
usage_flags
}
}
#[cfg(feature = "interface")]
impl From for UsageFlags {
fn from(flags: psa_crypto_sys::psa_key_usage_t) -> Self {
UsageFlags {
export: flags & psa_crypto_sys::PSA_KEY_USAGE_EXPORT > 0,
copy: false,
cache: false,
encrypt: flags & psa_crypto_sys::PSA_KEY_USAGE_ENCRYPT > 0,
decrypt: flags & psa_crypto_sys::PSA_KEY_USAGE_DECRYPT > 0,
sign_message: flags & psa_crypto_sys::PSA_KEY_USAGE_SIGN_MESSAGE > 0,
verify_message: flags & psa_crypto_sys::PSA_KEY_USAGE_VERIFY_MESSAGE > 0,
sign_hash: flags & psa_crypto_sys::PSA_KEY_USAGE_SIGN_HASH > 0,
verify_hash: flags & psa_crypto_sys::PSA_KEY_USAGE_VERIFY_HASH > 0,
derive: flags & psa_crypto_sys::PSA_KEY_USAGE_DERIVE > 0,
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for psa_crypto_sys::psa_ecc_family_t {
type Error = Error;
fn try_from(family: EccFamily) -> Result {
match family {
EccFamily::SecpK1 => Ok(psa_crypto_sys::PSA_ECC_FAMILY_SECP_K1),
EccFamily::SecpR1 => Ok(psa_crypto_sys::PSA_ECC_FAMILY_SECP_R1),
EccFamily::SecpR2 => Ok(psa_crypto_sys::PSA_ECC_FAMILY_SECP_R2),
EccFamily::SectK1 => Ok(psa_crypto_sys::PSA_ECC_FAMILY_SECT_K1),
EccFamily::SectR1 => Ok(psa_crypto_sys::PSA_ECC_FAMILY_SECT_R1),
EccFamily::SectR2 => Ok(psa_crypto_sys::PSA_ECC_FAMILY_SECT_R2),
EccFamily::BrainpoolPR1 => Ok(psa_crypto_sys::PSA_ECC_FAMILY_BRAINPOOL_P_R1),
EccFamily::Frp => Err(Error::NotSupported),
EccFamily::Montgomery => Ok(psa_crypto_sys::PSA_ECC_FAMILY_MONTGOMERY),
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for EccFamily {
type Error = Error;
fn try_from(family: psa_crypto_sys::psa_ecc_family_t) -> Result {
match family {
psa_crypto_sys::PSA_ECC_FAMILY_SECP_K1 => Ok(EccFamily::SecpK1),
psa_crypto_sys::PSA_ECC_FAMILY_SECP_R1 => Ok(EccFamily::SecpR1),
psa_crypto_sys::PSA_ECC_FAMILY_SECP_R2 => Ok(EccFamily::SecpR2),
psa_crypto_sys::PSA_ECC_FAMILY_SECT_R1 => Ok(EccFamily::SectR1),
psa_crypto_sys::PSA_ECC_FAMILY_SECT_R2 => Ok(EccFamily::SectR2),
psa_crypto_sys::PSA_ECC_FAMILY_BRAINPOOL_P_R1 => Ok(EccFamily::BrainpoolPR1),
//psa_crypto_sys::PSA_ECC_FAMILY_FRP => Ok(EccFamily::Frp),
psa_crypto_sys::PSA_ECC_FAMILY_MONTGOMERY => Ok(EccFamily::Montgomery),
f => {
error!("Can not recognize the ECC family: {:?}.", f);
Err(Error::GenericError)
}
}
}
}
#[cfg(feature = "interface")]
impl From for psa_crypto_sys::psa_dh_family_t {
fn from(group: DhFamily) -> Self {
match group {
DhFamily::Rfc7919 => psa_crypto_sys::PSA_DH_FAMILY_RFC7919,
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for DhFamily {
type Error = Error;
fn try_from(group: psa_crypto_sys::psa_dh_family_t) -> Result {
match group {
psa_crypto_sys::PSA_DH_FAMILY_RFC7919 => Ok(DhFamily::Rfc7919),
f => {
error!("Can not recognize the DH family: {:?}.", f);
Err(Error::GenericError)
}
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for psa_crypto_sys::psa_key_type_t {
type Error = Error;
fn try_from(key_type: Type) -> Result {
match key_type {
Type::RawData => Ok(psa_crypto_sys::PSA_KEY_TYPE_RAW_DATA),
Type::Hmac => Ok(psa_crypto_sys::PSA_KEY_TYPE_HMAC),
Type::Derive => Ok(psa_crypto_sys::PSA_KEY_TYPE_DERIVE),
Type::Aes => Ok(psa_crypto_sys::PSA_KEY_TYPE_AES),
Type::Des => Ok(psa_crypto_sys::PSA_KEY_TYPE_DES),
Type::Camellia => Ok(psa_crypto_sys::PSA_KEY_TYPE_CAMELLIA),
Type::Arc4 => Ok(psa_crypto_sys::PSA_KEY_TYPE_ARC4),
Type::Chacha20 => Ok(psa_crypto_sys::PSA_KEY_TYPE_CHACHA20),
Type::RsaPublicKey => Ok(psa_crypto_sys::PSA_KEY_TYPE_RSA_PUBLIC_KEY),
Type::RsaKeyPair => Ok(psa_crypto_sys::PSA_KEY_TYPE_RSA_KEY_PAIR),
Type::EccKeyPair { curve_family } => Ok(psa_crypto_sys::PSA_KEY_TYPE_ECC_KEY_PAIR(
curve_family.try_into()?,
)),
Type::EccPublicKey { curve_family } => Ok(psa_crypto_sys::PSA_KEY_TYPE_ECC_PUBLIC_KEY(
curve_family.try_into()?,
)),
Type::DhKeyPair { group_family } => Ok(psa_crypto_sys::PSA_KEY_TYPE_DH_KEY_PAIR(
group_family.into(),
)),
Type::DhPublicKey { group_family } => Ok(psa_crypto_sys::PSA_KEY_TYPE_DH_PUBLIC_KEY(
group_family.into(),
)),
}
}
}
#[cfg(feature = "interface")]
impl TryFrom for Type {
type Error = Error;
fn try_from(key_type: psa_crypto_sys::psa_key_type_t) -> Result {
match key_type {
psa_crypto_sys::PSA_KEY_TYPE_RAW_DATA => Ok(Type::RawData),
psa_crypto_sys::PSA_KEY_TYPE_HMAC => Ok(Type::Hmac),
psa_crypto_sys::PSA_KEY_TYPE_DERIVE => Ok(Type::Derive),
psa_crypto_sys::PSA_KEY_TYPE_AES => Ok(Type::Aes),
psa_crypto_sys::PSA_KEY_TYPE_DES => Ok(Type::Des),
psa_crypto_sys::PSA_KEY_TYPE_CAMELLIA => Ok(Type::Camellia),
psa_crypto_sys::PSA_KEY_TYPE_ARC4 => Ok(Type::Arc4),
psa_crypto_sys::PSA_KEY_TYPE_CHACHA20 => Ok(Type::Chacha20),
psa_crypto_sys::PSA_KEY_TYPE_RSA_PUBLIC_KEY => Ok(Type::RsaPublicKey),
psa_crypto_sys::PSA_KEY_TYPE_RSA_KEY_PAIR => Ok(Type::RsaKeyPair),
key_type if psa_crypto_sys::PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) => {
Ok(Type::EccKeyPair {
curve_family: psa_crypto_sys::PSA_KEY_TYPE_ECC_GET_FAMILY(key_type)
.try_into()?,
})
}
key_type if psa_crypto_sys::PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) => {
Ok(Type::EccPublicKey {
curve_family: psa_crypto_sys::PSA_KEY_TYPE_ECC_GET_FAMILY(key_type)
.try_into()?,
})
}
key_type if psa_crypto_sys::PSA_KEY_TYPE_IS_DH_PUBLIC_KEY(key_type) => {
Ok(Type::DhPublicKey {
group_family: psa_crypto_sys::PSA_KEY_TYPE_DH_GET_FAMILY(key_type)
.try_into()?,
})
}
key_type if psa_crypto_sys::PSA_KEY_TYPE_IS_DH_KEY_PAIR(key_type) => {
Ok(Type::DhKeyPair {
group_family: psa_crypto_sys::PSA_KEY_TYPE_DH_GET_FAMILY(key_type)
.try_into()?,
})
}
key_type => {
error!("Can not recognize the key type: {:?}.", key_type);
Err(Error::GenericError)
}
}
}
}
#[cfg(test)]
mod tests {
use super::{Attributes, EccFamily, Lifetime, Policy, Type, UsageFlags};
use crate::types::algorithm::{
Aead, AeadWithDefaultLengthTag, Algorithm, AsymmetricSignature, Cipher, FullLengthMac,
Hash, Mac, SignHash,
};
use core::convert::TryInto;
#[test]
fn usage_flags() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let mut attributes = Attributes {
key_type: Type::RsaKeyPair,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: false,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(!attributes.is_exportable());
assert!(!attributes.is_hash_signable());
assert!(!attributes.is_hash_verifiable());
attributes.policy.usage_flags.export = true;
assert!(attributes.is_exportable());
assert!(!attributes.is_hash_signable());
assert!(!attributes.is_hash_verifiable());
attributes.policy.usage_flags.sign_hash = true;
assert!(attributes.is_exportable());
assert!(attributes.is_hash_signable());
assert!(!attributes.is_hash_verifiable());
attributes.policy.usage_flags.verify_hash = true;
assert!(attributes.is_exportable());
assert!(attributes.is_hash_signable());
assert!(attributes.is_hash_verifiable());
assert!(!attributes.is_derivable());
attributes.policy.usage_flags.derive = true;
assert!(attributes.is_derivable())
}
#[test]
fn permits_good_alg() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let attributes = Attributes {
key_type: Type::Hmac,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: true,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(attributes.is_alg_permitted(alg));
}
#[test]
fn permits_bad_alg() {
let permitted_alg = Algorithm::Mac(Mac::FullLength(FullLengthMac::Hmac {
hash_alg: Hash::Sha1,
}));
let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha1.into(),
});
let attributes = Attributes {
key_type: Type::Hmac,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: true,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(!attributes.is_alg_permitted(alg));
}
#[test]
fn permits_wildcard_alg() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: SignHash::Any,
});
let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha1.into(),
});
let attributes = Attributes {
key_type: Type::Hmac,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: true,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(attributes.is_alg_permitted(alg));
}
#[test]
fn permits_bad_wildcard_alg() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: SignHash::Any,
});
let attributes = Attributes {
key_type: Type::Hmac,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: true,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(!attributes.is_alg_permitted(alg));
}
#[test]
fn compat_rsa() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let mut attributes = Attributes {
key_type: Type::RsaKeyPair,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: false,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(attributes.is_compatible_with_alg(alg));
attributes.key_type = Type::RsaPublicKey;
assert!(attributes.is_compatible_with_alg(alg));
}
#[test]
fn compat_raw_data() {
let permitted_alg = Algorithm::None;
let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let attributes = Attributes {
key_type: Type::RawData,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: false,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(!attributes.is_compatible_with_alg(alg));
}
#[test]
fn compat_block_cipher() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let mut alg = Algorithm::Cipher(Cipher::Ofb);
let mut attributes = Attributes {
key_type: Type::Aes,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: false,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(attributes.is_compatible_with_alg(alg));
attributes.key_type = Type::Des;
assert!(attributes.is_compatible_with_alg(alg));
attributes.key_type = Type::Camellia;
assert!(attributes.is_compatible_with_alg(alg));
alg = Algorithm::Aead(Aead::AeadWithDefaultLengthTag(
AeadWithDefaultLengthTag::Ccm,
));
assert!(attributes.is_compatible_with_alg(alg));
attributes.key_type = Type::Des;
assert!(!attributes.is_compatible_with_alg(alg));
}
#[test]
fn compat_chacha() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let alg = Algorithm::Aead(Aead::AeadWithDefaultLengthTag(
AeadWithDefaultLengthTag::Chacha20Poly1305,
));
let attributes = Attributes {
key_type: Type::Chacha20,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: false,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(attributes.is_compatible_with_alg(alg));
}
#[test]
fn bad_compat() {
let permitted_alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let alg = Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
});
let attributes = Attributes {
key_type: Type::Hmac,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: false,
verify_message: false,
sign_hash: false,
verify_hash: false,
derive: false,
},
permitted_algorithms: permitted_alg,
},
};
assert!(!attributes.is_compatible_with_alg(alg));
}
#[test]
fn convert() {
let mut attrs = unsafe { psa_crypto_sys::psa_key_attributes_init() };
unsafe {
psa_crypto_sys::psa_set_key_lifetime(
&mut attrs,
psa_crypto_sys::PSA_KEY_LIFETIME_VOLATILE,
)
};
unsafe {
psa_crypto_sys::psa_set_key_usage_flags(
&mut attrs,
psa_crypto_sys::PSA_KEY_USAGE_SIGN_MESSAGE
| psa_crypto_sys::PSA_KEY_USAGE_VERIFY_MESSAGE,
)
};
unsafe {
psa_crypto_sys::psa_set_key_algorithm(
&mut attrs,
psa_crypto_sys::PSA_ALG_ECDSA(psa_crypto_sys::PSA_ALG_SHA_256),
)
};
unsafe {
psa_crypto_sys::psa_set_key_type(
&mut attrs,
psa_crypto_sys::PSA_KEY_TYPE_ECC_KEY_PAIR(psa_crypto_sys::PSA_ECC_FAMILY_SECP_K1),
)
};
unsafe { psa_crypto_sys::psa_set_key_bits(&mut attrs, 2048) };
assert_eq!(
Attributes {
key_type: Type::EccKeyPair {
curve_family: EccFamily::SecpK1,
},
bits: 2048,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
export: false,
copy: false,
cache: false,
encrypt: false,
decrypt: false,
sign_message: true,
verify_message: true,
sign_hash: false,
verify_hash: false,
derive: false,
},
permitted_algorithms: AsymmetricSignature::Ecdsa {
hash_alg: Hash::Sha256.into(),
}
.into(),
},
},
attrs.try_into().unwrap()
);
}
}
psa-crypto-0.9.2/src/types/key_derivation.rs 0000644 0000000 0000000 00000024643 10461020230 0017263 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PSA Key Derivation Operation types
use super::algorithm::{Hash, KeyDerivation, RawKeyAgreement};
use super::key::Id;
#[cfg(feature = "operations")]
use super::status::{Error, Result, Status};
#[cfg(feature = "operations")]
use core::convert::{From, TryFrom};
/// Key derivation operation for deriving keys from existing sources
#[derive(Debug, Clone, Copy)]
pub struct Operation<'a> {
/// Key derivation algorithm and inputs
pub inputs: Inputs<'a>,
/// Maximum capacity of a key derivation operation
pub capacity: Option,
}
/// Wrapper around KeyDerivation to enforce correct `Input`s
#[derive(Debug, Clone, Copy)]
pub enum Inputs<'a> {
/// HKDF algorithm.
Hkdf {
/// A hash algorithm to use
hash_alg: Hash,
/// Salt, used in the "extract" step. It is optional; if omitted, the derivation uses an empty salt.
/// Typically a direct input, can also be a key of type `RawData`.
salt: Option>,
/// Secret, used in the "extract" step. This is typically a key of type `Derive` , or the shared secret
/// resulting from a key agreement, using `Input::KeyAgreement`.
/// Must be a key or key agreement input if used with `psa_key_derivation_output_key`.
secret: InputSecret<'a>,
/// Info, used in the "expand" step. Typically a direct input, can also be a key of type `RawData`.
info: Input<'a>,
},
/// TLS-1.2 PRF algorithm.
Tls12Prf {
/// A hash algorithm to use.
hash_alg: Hash,
/// Seed, typically a direct input, can also be a key of type `RawData`.
seed: Input<'a>,
/// Secret, used in the "extract" step. This is typically a key of type `Derive` , or the shared secret
/// resulting from a key agreement, using `Input::KeyAgreement`.
/// Must be a key or key agreement input if used with `psa_key_derivation_output_key`.
secret: InputSecret<'a>,
/// Label. Typically a direct input, can also be a key of type `RawData`.
label: Input<'a>,
},
/// TLS-1.2 PSK-to-MasterSecret algorithm.
Tls12PskToMs {
/// A hash algorithm to use.
hash_alg: Hash,
/// Seed, typically a direct input, can also be a key of type `RawData`.
seed: Input<'a>,
/// Secret, used in the "extract" step. This is typically a key of type `Derive` , or the shared secret
/// resulting from a key agreement, using `Input::KeyAgreement`.
/// Must be a key or key agreement input if used with `psa_key_derivation_output_key`.
/// Must not be larger than `PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE`.
secret: InputSecret<'a>,
/// Label. Typically a direct input, can also be a key of type `RawData`.
label: Input<'a>,
},
}
/// Enumeration of the step of a key derivation.
#[cfg(feature = "operations")]
#[derive(Debug, Clone, Copy)]
enum DerivationStep {
/// A secret input for key derivation.
Secret,
/// A label for key derivation.
Label,
/// A context for key derivation.
//Context, In PSA spec but not in Mbed Crypto
/// A salt for key derivation.
Salt,
/// An information string for key derivation.
Info,
/// A seed for key derivation.
Seed,
}
#[cfg(feature = "operations")]
impl From for psa_crypto_sys::psa_key_derivation_step_t {
fn from(derivation_step: DerivationStep) -> Self {
match derivation_step {
DerivationStep::Secret => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_SECRET,
DerivationStep::Label => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_LABEL,
DerivationStep::Salt => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_SALT,
//DerivationStep::Context => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_CONTEXT, In PSA spec but not in Mbed Crypto
DerivationStep::Info => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_INFO,
DerivationStep::Seed => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_SEED,
}
}
}
#[cfg(feature = "interface")]
impl From> for psa_crypto_sys::psa_algorithm_t {
fn from(key_derivation_with_inputs: Inputs) -> Self {
key_derivation_with_inputs.key_derivation().into()
}
}
impl Inputs<'_> {
/// Retrieve key derivation algorithm without inputs
pub fn key_derivation(&self) -> KeyDerivation {
match self {
Inputs::Hkdf { hash_alg, .. } => KeyDerivation::Hkdf {
hash_alg: *hash_alg,
},
Inputs::Tls12Prf { hash_alg, .. } => KeyDerivation::Tls12Prf {
hash_alg: *hash_alg,
},
Inputs::Tls12PskToMs { hash_alg, .. } => KeyDerivation::Tls12PskToMs {
hash_alg: *hash_alg,
},
}
}
#[cfg(feature = "operations")]
pub(crate) fn apply_inputs_to_op(
&self,
op: &mut psa_crypto_sys::psa_key_derivation_operation_t,
) -> Result<()> {
match self {
Inputs::Hkdf {
salt, secret, info, ..
} => {
if let Some(salt) = salt {
Inputs::apply_input_step_to_op(op, DerivationStep::Salt, salt)?;
}
Inputs::apply_input_secret_step_to_op(op, secret)?;
Inputs::apply_input_step_to_op(op, DerivationStep::Info, info)
}
Inputs::Tls12Prf {
seed,
secret,
label,
..
}
| Inputs::Tls12PskToMs {
seed,
secret,
label,
..
} => {
Inputs::apply_input_step_to_op(op, DerivationStep::Seed, seed)?;
Inputs::apply_input_secret_step_to_op(op, secret)?;
Inputs::apply_input_step_to_op(op, DerivationStep::Label, label)
}
}
}
#[cfg(feature = "operations")]
fn apply_input_step_to_op(
op: &mut psa_crypto_sys::psa_key_derivation_operation_t,
step: DerivationStep,
input: &Input,
) -> Result<()> {
match input {
Input::Bytes(bytes) => Status::from(unsafe {
psa_crypto_sys::psa_key_derivation_input_bytes(
op,
step.into(),
bytes.as_ptr(),
bytes.len(),
)
})
.to_result(),
Input::Key(key_id) => Status::from(unsafe {
psa_crypto_sys::psa_key_derivation_input_key(op, step.into(), key_id.0)
})
.to_result(),
}
}
#[cfg(feature = "operations")]
fn apply_input_secret_step_to_op(
op: &mut psa_crypto_sys::psa_key_derivation_operation_t,
secret: &InputSecret,
) -> Result<()> {
match secret {
InputSecret::Input(input) => {
Inputs::apply_input_step_to_op(op, DerivationStep::Secret, input)
}
InputSecret::KeyAgreement {
private_key,
peer_key,
..
} => Status::from(unsafe {
psa_crypto_sys::psa_key_derivation_key_agreement(
op,
DerivationStep::Secret.into(),
private_key.0,
(**peer_key).as_ptr(),
peer_key.len(),
)
})
.to_result(),
}
}
}
/// Enumeration of supported input data for different input steps
#[derive(Debug, Clone, Copy)]
pub enum Input<'a> {
/// Byte input for key derivation
Bytes(&'a [u8]),
/// Key input for key derivation
Key(Id),
}
/// Enumeration of supported input data for different input steps
#[derive(Debug, Clone, Copy)]
pub enum InputSecret<'a> {
/// Regular input of bytes or a key ID
Input(Input<'a>),
/// Output of a key agreement
KeyAgreement {
/// Key agreement algorithm to use
alg: RawKeyAgreement,
/// Private key to use in key agreement
private_key: Id,
/// Public key data of peer key to use. Must be in the same format that `key_management::import` accepts for the public key
/// corresponding to the type of private key.
peer_key: &'a [u8],
},
}
impl<'a> From> for InputSecret<'a> {
fn from(input: Input<'a>) -> Self {
InputSecret::<'a>::Input(input)
}
}
#[cfg(feature = "operations")]
impl TryFrom> for psa_crypto_sys::psa_key_derivation_operation_t {
type Error = Error;
fn try_from(operation: Operation) -> Result {
let mut op = psa_crypto_sys::psa_key_derivation_operation_init();
let mut setup_deriv_op = || -> Result<()> {
let mut key_derivation_alg: psa_crypto_sys::psa_algorithm_t =
operation.inputs.key_derivation().into();
// If key agreement is used as the input for secret step, extract key agreement alg and combine it with key derivation alg
let secret = match operation.inputs {
Inputs::Hkdf { secret, .. }
| Inputs::Tls12Prf { secret, .. }
| Inputs::Tls12PskToMs { secret, .. } => secret,
};
if let InputSecret::KeyAgreement { alg, .. } = secret {
key_derivation_alg = unsafe {
psa_crypto_sys::PSA_ALG_KEY_AGREEMENT(alg.into(), key_derivation_alg)
};
}
Status::from(unsafe {
psa_crypto_sys::psa_key_derivation_setup(&mut op, key_derivation_alg)
})
.to_result()?;
operation.inputs.apply_inputs_to_op(&mut op)
};
if let Err(error) = setup_deriv_op() {
Operation::abort(op)?;
return Err(error);
}
if let Some(capacity) = operation.capacity {
// Maybe best to add capacity to the algorithms for static check as some don't support it
Status::from(unsafe {
psa_crypto_sys::psa_key_derivation_set_capacity(&mut op, capacity)
})
.to_result()?;
}
Ok(op)
}
}
impl Operation<'_> {
/// Clears operation C struct and consumes KeyDerivationOperation struct
#[cfg(feature = "operations")]
pub(crate) fn abort(mut op: psa_crypto_sys::psa_key_derivation_operation_t) -> Result<()> {
Status::from(unsafe { psa_crypto_sys::psa_key_derivation_abort(&mut op) }).to_result()
}
}
psa-crypto-0.9.2/src/types/mod.rs 0000644 0000000 0000000 00000000267 10461020230 0015022 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PSA Types
pub mod algorithm;
pub mod key;
pub mod key_derivation;
pub mod status;
psa-crypto-0.9.2/src/types/status.rs 0000644 0000000 0000000 00000025352 10461020230 0015570 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PSA Status Codes
//!
//! This module defines success and error codes returned by any PSA function.
use log::error;
use zeroize::Zeroize;
#[cfg(not(feature = "no-std"))]
use std::fmt;
/// Result type returned by any PSA operation
pub type Result = core::result::Result;
/// Definition of a PSA status code
#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
pub enum Status {
/// Status code for success
Success,
/// Status codes for errors
Error(Error),
}
impl Status {
/// Convert the Status into a Result returning the empty tuple
///
/// # Example
///
/// ```
/// use psa_crypto::types::status::{Status, Error};
///
/// let status_err = Status::Error(Error::GenericError);
/// assert!(status_err.to_result().is_err());
///
/// let status_ok = Status::Success;
/// assert!(status_ok.to_result().is_ok());
/// ```
pub fn to_result(self) -> Result<()> {
match self {
Status::Success => Ok(()),
Status::Error(error) => Err(error),
}
}
}
/// Definition of a PSA status code
#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
pub enum Error {
/// An error occurred that does not correspond to any defined failure cause
GenericError,
/// The requested operation or a parameter is not supported by this implementation
NotSupported,
/// The requested action is denied by a policy
NotPermitted,
/// An output buffer is too small
BufferTooSmall,
/// Asking for an item that already exists
AlreadyExists,
/// Asking for an item that doesn't exist
DoesNotExist,
/// The requested action cannot be performed in the current state
BadState,
/// The parameters passed to the function are invalid
InvalidArgument,
/// There is not enough runtime memory
InsufficientMemory,
/// There is not enough persistent storage
InsufficientStorage,
/// There was a communication failure inside the implementation
CommunicationFailure,
/// There was a storage failure that may have led to data loss
StorageFailure,
/// Stored data has been corrupted
DataCorrupt,
/// Data read from storage is not valid for the implementation
DataInvalid,
/// A hardware failure was detected
HardwareFailure,
/// A tampering attempt was detected
CorruptionDetected,
/// There is not enough entropy to generate random data needed for the requested action
InsufficientEntropy,
/// The signature, MAC or hash is incorrect
InvalidSignature,
/// The decrypted padding is incorrect
InvalidPadding,
/// Insufficient data when attempting to read from a resource
InsufficientData,
/// The key handle is not valid
InvalidHandle,
}
#[cfg(not(feature = "no-std"))]
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::GenericError => write!(
f,
"An error occurred that does not correspond to any defined failure cause"
),
Error::NotSupported => write!(
f,
"The requested operation or a parameter is not supported by this implementation"
),
Error::NotPermitted => write!(f, "The requested action is denied by a policy"),
Error::BufferTooSmall => write!(f, "An output buffer is too small"),
Error::AlreadyExists => write!(f, "Asking for an item that already exists"),
Error::DoesNotExist => write!(f, "Asking for an item that doesn't exist"),
Error::BadState => write!(
f,
"The requested action cannot be performed in the current state"
),
Error::InvalidArgument => {
write!(f, "The parameters passed to the function are invalid")
}
Error::InsufficientMemory => write!(f, "There is not enough runtime memory"),
Error::InsufficientStorage => write!(f, "There is not enough persistent storage"),
Error::CommunicationFailure => write!(
f,
"There was a communication failure inside the implementation"
),
Error::StorageFailure => write!(
f,
"There was a storage failure that may have led to data loss"
),
Error::DataCorrupt => write!(f, "Stored data has been corrupted"),
Error::DataInvalid => write!(
f,
"Data read from storage is not valid for the implementation"
),
Error::HardwareFailure => write!(f, "A hardware failure was detected"),
Error::CorruptionDetected => write!(f, "A tampering attempt was detected"),
Error::InsufficientEntropy => write!(
f,
"There is not enough entropy to generate random data needed for the requested action"
),
Error::InvalidSignature => write!(
f,
"The signature, MAC or hash is incorrect"
),
Error::InvalidPadding => write!(
f,
"The decrypted padding is incorrect"
),
Error::InsufficientData => write!(
f,
"Insufficient data when attempting to read from a resource"
),
Error::InvalidHandle => write!(
f,
"The key handle is not valid"
),
}
}
}
#[cfg(not(feature = "no-std"))]
impl std::error::Error for Error {}
impl From for Status {
fn from(error: Error) -> Self {
Status::Error(error)
}
}
impl From for Status {
fn from(status: psa_crypto_sys::psa_status_t) -> Self {
match status {
psa_crypto_sys::PSA_SUCCESS => Status::Success,
psa_crypto_sys::PSA_ERROR_GENERIC_ERROR => Error::GenericError.into(),
psa_crypto_sys::PSA_ERROR_NOT_SUPPORTED => Error::NotSupported.into(),
psa_crypto_sys::PSA_ERROR_NOT_PERMITTED => Error::NotPermitted.into(),
psa_crypto_sys::PSA_ERROR_BUFFER_TOO_SMALL => Error::BufferTooSmall.into(),
psa_crypto_sys::PSA_ERROR_ALREADY_EXISTS => Error::AlreadyExists.into(),
psa_crypto_sys::PSA_ERROR_DOES_NOT_EXIST => Error::DoesNotExist.into(),
psa_crypto_sys::PSA_ERROR_BAD_STATE => Error::BadState.into(),
psa_crypto_sys::PSA_ERROR_INVALID_ARGUMENT => Error::InvalidArgument.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_MEMORY => Error::InsufficientMemory.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_STORAGE => Error::InsufficientStorage.into(),
psa_crypto_sys::PSA_ERROR_COMMUNICATION_FAILURE => Error::CommunicationFailure.into(),
psa_crypto_sys::PSA_ERROR_STORAGE_FAILURE => Error::StorageFailure.into(),
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE => Error::HardwareFailure.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_ENTROPY => Error::InsufficientEntropy.into(),
psa_crypto_sys::PSA_ERROR_INVALID_SIGNATURE => Error::InvalidSignature.into(),
psa_crypto_sys::PSA_ERROR_INVALID_PADDING => Error::InvalidPadding.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA => Error::InsufficientData.into(),
psa_crypto_sys::PSA_ERROR_INVALID_HANDLE => Error::InvalidHandle.into(),
psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED => Error::CorruptionDetected.into(),
psa_crypto_sys::PSA_ERROR_DATA_CORRUPT => Error::DataCorrupt.into(),
psa_crypto_sys::PSA_ERROR_DATA_INVALID => Error::DataInvalid.into(),
s => {
error!("{} not recognised as a valid PSA status.", s);
Status::Error(Error::GenericError)
}
}
}
}
impl From for psa_crypto_sys::psa_status_t {
fn from(status: Status) -> psa_crypto_sys::psa_status_t {
match status {
Status::Success => psa_crypto_sys::PSA_SUCCESS,
Status::Error(error) => error.into(),
}
}
}
impl From for psa_crypto_sys::psa_status_t {
fn from(error: Error) -> psa_crypto_sys::psa_status_t {
match error {
Error::GenericError => psa_crypto_sys::PSA_ERROR_GENERIC_ERROR,
Error::NotSupported => psa_crypto_sys::PSA_ERROR_NOT_SUPPORTED,
Error::NotPermitted => psa_crypto_sys::PSA_ERROR_NOT_PERMITTED,
Error::BufferTooSmall => psa_crypto_sys::PSA_ERROR_BUFFER_TOO_SMALL,
Error::AlreadyExists => psa_crypto_sys::PSA_ERROR_ALREADY_EXISTS,
Error::DoesNotExist => psa_crypto_sys::PSA_ERROR_DOES_NOT_EXIST,
Error::BadState => psa_crypto_sys::PSA_ERROR_BAD_STATE,
Error::InvalidArgument => psa_crypto_sys::PSA_ERROR_INVALID_ARGUMENT,
Error::InsufficientMemory => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_MEMORY,
Error::InsufficientStorage => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_STORAGE,
Error::CommunicationFailure => psa_crypto_sys::PSA_ERROR_COMMUNICATION_FAILURE,
Error::StorageFailure => psa_crypto_sys::PSA_ERROR_STORAGE_FAILURE,
Error::DataCorrupt => psa_crypto_sys::PSA_ERROR_DATA_CORRUPT,
Error::DataInvalid => psa_crypto_sys::PSA_ERROR_DATA_INVALID,
Error::HardwareFailure => psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE,
Error::CorruptionDetected => psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED,
Error::InsufficientEntropy => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_ENTROPY,
Error::InvalidSignature => psa_crypto_sys::PSA_ERROR_INVALID_SIGNATURE,
Error::InvalidPadding => psa_crypto_sys::PSA_ERROR_INVALID_PADDING,
Error::InsufficientData => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA,
Error::InvalidHandle => psa_crypto_sys::PSA_ERROR_INVALID_HANDLE,
}
}
}
impl From for Result<()> {
fn from(status: Status) -> Self {
status.to_result()
}
}
#[cfg(test)]
mod test {
use crate::types::status::{Error, Status};
#[test]
fn conversion() {
assert_eq!(psa_crypto_sys::PSA_SUCCESS, Status::Success.into());
assert_eq!(
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE,
Status::Error(Error::HardwareFailure).into()
);
assert_eq!(
Status::Error(Error::HardwareFailure),
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE.into()
);
assert_ne!(
Status::Error(Error::InsufficientEntropy),
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE.into()
);
assert_eq!(Status::Error(Error::GenericError), 0x0EAD_BEEF.into());
}
}
psa-crypto-0.9.2/tests/aead.rs 0000644 0000000 0000000 00000015125 10461020230 0014343 0 ustar 0000000 0000000 use psa_crypto::operations::{aead, key_management};
use psa_crypto::types::algorithm::{Aead, AeadWithDefaultLengthTag};
use psa_crypto::types::key::{Attributes, Lifetime, Policy, Type, UsageFlags};
use psa_crypto::types::status::Error;
use std::convert::TryInto;
const KEY_DATA: [u8; 16] = [
0x41, 0x89, 0x35, 0x1B, 0x5C, 0xAE, 0xA3, 0x75, 0xA0, 0x29, 0x9E, 0x81, 0xC6, 0x21, 0xBF, 0x43,
];
const NONCE: [u8; 13] = [
0x48, 0xc0, 0x90, 0x69, 0x30, 0x56, 0x1e, 0x0a, 0xb0, 0xef, 0x4c, 0xd9, 0x72,
];
const ADDITIONAL_DATA: [u8; 32] = [
0x40, 0xa2, 0x7c, 0x1d, 0x1e, 0x23, 0xea, 0x3d, 0xbe, 0x80, 0x56, 0xb2, 0x77, 0x48, 0x61, 0xa4,
0xa2, 0x01, 0xcc, 0xe4, 0x9f, 0x19, 0x99, 0x7d, 0x19, 0x20, 0x6d, 0x8c, 0x8a, 0x34, 0x39, 0x51,
];
const DECRYPTED_DATA: [u8; 24] = [
0x45, 0x35, 0xd1, 0x2b, 0x43, 0x77, 0x92, 0x8a, 0x7c, 0x0a, 0x61, 0xc9, 0xf8, 0x25, 0xa4, 0x86,
0x71, 0xea, 0x05, 0x91, 0x07, 0x48, 0xc8, 0xef,
];
const ENCRYPTED_DATA: [u8; 40] = [
0x26, 0xc5, 0x69, 0x61, 0xc0, 0x35, 0xa7, 0xe4, 0x52, 0xcc, 0xe6, 0x1b, 0xc6, 0xee, 0x22, 0x0d,
0x77, 0xb3, 0xf9, 0x4d, 0x18, 0xfd, 0x10, 0xb6, 0xd8, 0x0e, 0x8b, 0xf8, 0x0f, 0x4a, 0x46, 0xca,
0xb0, 0x6d, 0x43, 0x13, 0xf0, 0xdb, 0x9b, 0xe9,
];
#[test]
fn aead_encrypt_aes_ccm() {
let alg = Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm);
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_encrypt();
let attributes = Attributes {
key_type: Type::Aes,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: alg.into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
let output_buffer_size = unsafe {
psa_crypto_sys::PSA_AEAD_ENCRYPT_OUTPUT_SIZE(
attributes.key_type.try_into().unwrap(),
alg.into(),
DECRYPTED_DATA.len(),
)
};
let mut output_buffer = vec![0; output_buffer_size];
let length = aead::encrypt(
my_key,
alg,
&NONCE,
&ADDITIONAL_DATA,
&DECRYPTED_DATA,
&mut output_buffer,
)
.unwrap();
output_buffer.resize(length, 0);
assert_eq!(&ENCRYPTED_DATA[..], &output_buffer[..]);
}
#[test]
fn aead_encrypt_aes_ccm_no_encrypt_usage_flag() {
let alg = Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm);
let usage_flags: UsageFlags = Default::default();
let attributes = Attributes {
key_type: Type::Aes,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: alg.into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
let output_buffer_size = unsafe {
psa_crypto_sys::PSA_AEAD_ENCRYPT_OUTPUT_SIZE(
attributes.key_type.try_into().unwrap(),
alg.into(),
DECRYPTED_DATA.len(),
)
};
let mut output_buffer = vec![0; output_buffer_size];
let result = aead::encrypt(
my_key,
alg,
&NONCE,
&ADDITIONAL_DATA,
&DECRYPTED_DATA,
&mut output_buffer,
);
assert_eq!(Err(Error::NotPermitted), result)
}
#[test]
fn aead_decrypt_aes_ccm() {
let alg = Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm);
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_decrypt();
let attributes = Attributes {
key_type: Type::Aes,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: alg.into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
let output_buffer_size = unsafe {
psa_crypto_sys::PSA_AEAD_DECRYPT_OUTPUT_SIZE(
attributes.key_type.try_into().unwrap(),
alg.into(),
ENCRYPTED_DATA.len(),
)
};
let mut output_buffer = vec![0; output_buffer_size];
let length = aead::decrypt(
my_key,
alg,
&NONCE,
&ADDITIONAL_DATA,
&ENCRYPTED_DATA,
&mut output_buffer,
)
.unwrap();
output_buffer.resize(length, 0);
assert_eq!(&DECRYPTED_DATA[..], &output_buffer[..]);
}
#[test]
fn aead_decrypt_aes_ccm_no_decrypt_usage_flag() {
let alg = Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm);
let usage_flags: UsageFlags = Default::default();
let attributes = Attributes {
key_type: Type::Aes,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: alg.into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
let output_buffer_size = unsafe {
psa_crypto_sys::PSA_AEAD_DECRYPT_OUTPUT_SIZE(
attributes.key_type.try_into().unwrap(),
alg.into(),
ENCRYPTED_DATA.len(),
)
};
let mut output_buffer = vec![0; output_buffer_size];
let result = aead::decrypt(
my_key,
alg,
&NONCE,
&ADDITIONAL_DATA,
&ENCRYPTED_DATA,
&mut output_buffer,
);
assert_eq!(Err(Error::NotPermitted), result);
}
#[test]
fn aead_decrypt_aes_ccm_invalid_signature() {
const RANDOM_INPUT_DATA: [u8; 23] = [
0x08, 0xE8, 0xCF, 0x97, 0xD8, 0x20, 0xEA, 0x25, 0x84, 0x60, 0xE9, 0x6A, 0xD9, 0xCF, 0x52,
0x89, 0x05, 0x4D, 0x89, 0x5C, 0xEA, 0xC4, 0x7C,
];
let alg = Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm);
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_decrypt();
let attributes = Attributes {
key_type: Type::Aes,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: alg.into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
let output_buffer_size = unsafe {
psa_crypto_sys::PSA_AEAD_DECRYPT_OUTPUT_SIZE(
attributes.key_type.try_into().unwrap(),
alg.into(),
RANDOM_INPUT_DATA.len(),
)
};
let mut output_buffer = vec![0; output_buffer_size];
let result = aead::decrypt(
my_key,
alg,
&NONCE,
&ADDITIONAL_DATA,
&RANDOM_INPUT_DATA,
&mut output_buffer,
);
assert_eq!(Err(Error::InvalidSignature), result);
}
psa-crypto-0.9.2/tests/hash.rs 0000644 0000000 0000000 00000005542 10461020230 0014376 0 ustar 0000000 0000000 use psa_crypto::operations::hash;
use psa_crypto::types::algorithm::Hash;
#[test]
fn hash_compute_ripemd160() {
const MESSAGE: [u8; 3] = [0x61, 0x62, 0x63];
const HASH: [u8; 20] = [
0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, 0x4a, 0x8e, 0x98, 0xc6, 0xb0,
0x87, 0xf1, 0x5a, 0x0b, 0xfc,
];
psa_crypto::init().unwrap();
let hash_alg = Hash::Ripemd160;
let mut hash = vec![0; hash_alg.hash_length()];
let size = hash::hash_compute(hash_alg, &MESSAGE, &mut hash).unwrap();
hash.resize(size, 0);
assert_eq!(&HASH, &hash[..]);
}
#[test]
fn hash_compute_sha256() {
const MESSAGE: [u8; 3] = [0xb0, 0xbd, 0x69];
const HASH: [u8; 32] = [
0x40, 0x96, 0x80, 0x42, 0x21, 0x09, 0x3d, 0xdc, 0xcf, 0xbf, 0x46, 0x83, 0x14, 0x90, 0xea,
0x63, 0xe9, 0xe9, 0x94, 0x14, 0x85, 0x8f, 0x8d, 0x75, 0xff, 0x7f, 0x64, 0x2c, 0x7c, 0xa6,
0x18, 0x03,
];
psa_crypto::init().unwrap();
let hash_alg = Hash::Sha256;
let mut hash = vec![0; hash_alg.hash_length()];
let size = hash::hash_compute(hash_alg, &MESSAGE, &mut hash).unwrap();
hash.resize(size, 0);
assert_eq!(&HASH, &hash[..]);
}
#[test]
fn hash_compare_sha256() {
const MESSAGE: [u8; 3] = [0xb0, 0xbd, 0x69];
const HASH: [u8; 32] = [
0x40, 0x96, 0x80, 0x42, 0x21, 0x09, 0x3d, 0xdc, 0xcf, 0xbf, 0x46, 0x83, 0x14, 0x90, 0xea,
0x63, 0xe9, 0xe9, 0x94, 0x14, 0x85, 0x8f, 0x8d, 0x75, 0xff, 0x7f, 0x64, 0x2c, 0x7c, 0xa6,
0x18, 0x03,
];
psa_crypto::init().unwrap();
let hash_alg = Hash::Sha256;
hash::hash_compare(hash_alg, &MESSAGE, &HASH).unwrap();
}
#[test]
fn hash_compare_ripemd160() {
const MESSAGE: [u8; 3] = [0x61, 0x62, 0x63];
const HASH: [u8; 20] = [
0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, 0x4a, 0x8e, 0x98, 0xc6, 0xb0,
0x87, 0xf1, 0x5a, 0x0b, 0xfc,
];
psa_crypto::init().unwrap();
let hash_alg = Hash::Ripemd160;
hash::hash_compare(hash_alg, &MESSAGE, &HASH).unwrap();
}
#[test]
fn hash_compare_sha256_fail() {
const MESSAGE: [u8; 3] = [0xb0, 0xbd, 0x69];
const HASH: [u8; 20] = [
0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, 0x4a, 0x8e, 0x98, 0xc6, 0xb0,
0x87, 0xf1, 0x5a, 0x0b, 0xfc,
];
psa_crypto::init().unwrap();
let hash_alg = Hash::Sha256;
hash::hash_compare(hash_alg, &MESSAGE, &HASH).unwrap_err();
}
#[test]
fn hash_compare_ripemd160_fail() {
const MESSAGE: [u8; 3] = [0x61, 0x62, 0x63];
const HASH: [u8; 32] = [
0x40, 0x96, 0x80, 0x42, 0x21, 0x09, 0x3d, 0xdc, 0xcf, 0xbf, 0x46, 0x83, 0x14, 0x90, 0xea,
0x63, 0xe9, 0xe9, 0x94, 0x14, 0x85, 0x8f, 0x8d, 0x75, 0xff, 0x7f, 0x64, 0x2c, 0x7c, 0xa6,
0x18, 0x03,
];
psa_crypto::init().unwrap();
let hash_alg = Hash::Ripemd160;
hash::hash_compare(hash_alg, &MESSAGE, &HASH).unwrap_err();
}
psa-crypto-0.9.2/tests/key_agreement.rs 0000644 0000000 0000000 00000010214 10461020230 0016262 0 ustar 0000000 0000000 use psa_crypto::operations::{key_agreement, key_management};
use psa_crypto::types::algorithm::{KeyAgreement, RawKeyAgreement};
use psa_crypto::types::key::{Attributes, EccFamily, Lifetime, Policy, Type, UsageFlags};
use psa_crypto::types::status::Error;
const PEER_PUBLIC_KEY: [u8; 65] = [
0x04, 0xd1, 0x2d, 0xfb, 0x52, 0x89, 0xc8, 0xd4, 0xf8, 0x12, 0x08, 0xb7, 0x02, 0x70, 0x39, 0x8c,
0x34, 0x22, 0x96, 0x97, 0x0a, 0x0b, 0xcc, 0xb7, 0x4c, 0x73, 0x6f, 0xc7, 0x55, 0x44, 0x94, 0xbf,
0x63, 0x56, 0xfb, 0xf3, 0xca, 0x36, 0x6c, 0xc2, 0x3e, 0x81, 0x57, 0x85, 0x4c, 0x13, 0xc5, 0x8d,
0x6a, 0xac, 0x23, 0xf0, 0x46, 0xad, 0xa3, 0x0f, 0x83, 0x53, 0xe7, 0x4f, 0x33, 0x03, 0x98, 0x72,
0xab,
];
const OUR_KEY_DATA: [u8; 32] = [
0xc8, 0x8f, 0x01, 0xf5, 0x10, 0xd9, 0xac, 0x3f, 0x70, 0xa2, 0x92, 0xda, 0xa2, 0x31, 0x6d, 0xe5,
0x44, 0xe9, 0xaa, 0xb8, 0xaf, 0xe8, 0x40, 0x49, 0xc6, 0x2a, 0x9c, 0x57, 0x86, 0x2d, 0x14, 0x33,
];
const EXPECTED_OUTPUT: [u8; 32] = [
0xd6, 0x84, 0x0f, 0x6b, 0x42, 0xf6, 0xed, 0xaf, 0xd1, 0x31, 0x16, 0xe0, 0xe1, 0x25, 0x65, 0x20,
0x2f, 0xef, 0x8e, 0x9e, 0xce, 0x7d, 0xce, 0x03, 0x81, 0x24, 0x64, 0xd0, 0x4b, 0x94, 0x42, 0xde,
];
#[test]
fn key_agreement() {
let alg = RawKeyAgreement::Ecdh;
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_derive();
let attributes = Attributes {
key_type: Type::EccKeyPair {
curve_family: EccFamily::SecpR1,
},
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyAgreement::Raw(alg).into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &OUR_KEY_DATA).unwrap();
let mut output = vec![0; 1024];
let size =
key_agreement::raw_key_agreement(alg, my_key, &PEER_PUBLIC_KEY, &mut output).unwrap();
output.resize(size, 0);
assert_eq!(&EXPECTED_OUTPUT[..], &output[..])
}
#[test]
fn key_agreement_incompatible_keys() {
const RSA_PUB_KEY_DATA: [u8; 140] = [
48, 129, 137, 2, 129, 129, 0, 153, 165, 220, 135, 89, 101, 254, 229, 28, 33, 138, 247, 20,
102, 253, 217, 247, 246, 142, 107, 51, 40, 179, 149, 45, 117, 254, 236, 161, 109, 16, 81,
135, 72, 112, 132, 150, 175, 128, 173, 182, 122, 227, 214, 196, 130, 54, 239, 93, 5, 203,
185, 233, 61, 159, 156, 7, 161, 87, 48, 234, 105, 161, 108, 215, 211, 150, 168, 156, 212,
6, 63, 81, 24, 101, 72, 160, 97, 243, 142, 86, 10, 160, 122, 8, 228, 178, 252, 35, 209,
222, 228, 16, 143, 99, 143, 146, 241, 186, 187, 22, 209, 86, 141, 24, 159, 12, 146, 44,
111, 254, 183, 54, 229, 109, 28, 39, 22, 141, 173, 85, 26, 58, 9, 128, 27, 57, 131, 2, 3,
1, 0, 1,
];
let alg = RawKeyAgreement::Ecdh;
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_derive();
let attributes = Attributes {
key_type: Type::RsaPublicKey,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyAgreement::Raw(alg).into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &RSA_PUB_KEY_DATA).unwrap();
let mut output = vec![0; 1024];
let result = key_agreement::raw_key_agreement(alg, my_key, &PEER_PUBLIC_KEY, &mut output);
assert_eq!(Err(Error::InvalidArgument), result);
}
#[test]
fn key_agreement_no_derive_flag() {
let alg = RawKeyAgreement::Ecdh;
let usage_flags: UsageFlags = Default::default();
let attributes = Attributes {
key_type: Type::EccKeyPair {
curve_family: EccFamily::SecpR1,
},
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyAgreement::Raw(alg).into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &OUR_KEY_DATA).unwrap();
let mut output = vec![0; 1024];
let result = key_agreement::raw_key_agreement(alg, my_key, &PEER_PUBLIC_KEY, &mut output);
assert_eq!(Err(Error::NotPermitted), result);
}
psa-crypto-0.9.2/tests/key_derivation.rs 0000644 0000000 0000000 00000011351 10461020230 0016462 0 ustar 0000000 0000000 use psa_crypto::operations::{key_derivation, key_management};
use psa_crypto::types::algorithm::{Hash, KeyAgreement, KeyDerivation, RawKeyAgreement};
use psa_crypto::types::key::{Attributes, EccFamily, Lifetime, Policy, Type, UsageFlags};
use psa_crypto::types::key_derivation::{Input, InputSecret, Inputs, Operation};
const PEER_PUBLIC_KEY: [u8; 65] = [
0x04, 0xd1, 0x2d, 0xfb, 0x52, 0x89, 0xc8, 0xd4, 0xf8, 0x12, 0x08, 0xb7, 0x02, 0x70, 0x39, 0x8c,
0x34, 0x22, 0x96, 0x97, 0x0a, 0x0b, 0xcc, 0xb7, 0x4c, 0x73, 0x6f, 0xc7, 0x55, 0x44, 0x94, 0xbf,
0x63, 0x56, 0xfb, 0xf3, 0xca, 0x36, 0x6c, 0xc2, 0x3e, 0x81, 0x57, 0x85, 0x4c, 0x13, 0xc5, 0x8d,
0x6a, 0xac, 0x23, 0xf0, 0x46, 0xad, 0xa3, 0x0f, 0x83, 0x53, 0xe7, 0x4f, 0x33, 0x03, 0x98, 0x72,
0xab,
];
const PRIVATE_KEY_DATA: [u8; 32] = [
0xc8, 0x8f, 0x01, 0xf5, 0x10, 0xd9, 0xac, 0x3f, 0x70, 0xa2, 0x92, 0xda, 0xa2, 0x31, 0x6d, 0xe5,
0x44, 0xe9, 0xaa, 0xb8, 0xaf, 0xe8, 0x40, 0x49, 0xc6, 0x2a, 0x9c, 0x57, 0x86, 0x2d, 0x14, 0x33,
];
#[test]
fn output_key() {
const KEY_DATA: [u8; 23] = [0; 23];
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_derive();
let attributes = Attributes {
key_type: Type::Derive,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyDerivation::Hkdf {
hash_alg: Hash::Sha256,
}
.into(),
},
};
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_derive();
let derived_key_attributes = Attributes {
key_type: Type::RawData,
bits: 8,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyDerivation::Hkdf {
hash_alg: Hash::Sha256,
}
.into(),
},
};
psa_crypto::init().unwrap();
let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
let info = vec![20; 0x3f];
let operation = Operation {
inputs: Inputs::Hkdf {
hash_alg: Hash::Sha256,
salt: None,
secret: InputSecret::Input(Input::Key(my_key)),
info: Input::Bytes(&info),
},
capacity: None,
};
let _new_key = key_derivation::output_key(operation, derived_key_attributes, None).unwrap();
}
#[test]
#[ignore]
fn output_key_with_key_agreement() {
let key_agreement_alg = RawKeyAgreement::Ecdh;
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_derive();
let key_agr_attributes = Attributes {
key_type: Type::EccKeyPair {
curve_family: EccFamily::SecpR1,
},
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyAgreement::WithKeyDerivation {
ka_alg: key_agreement_alg,
kdf_alg: KeyDerivation::Hkdf {
hash_alg: Hash::Sha256,
},
}
.into(),
},
};
const KEY_DATA: [u8; 23] = [0; 23];
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_derive();
let attributes = Attributes {
key_type: Type::RawData,
bits: 0,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyAgreement::WithKeyDerivation {
ka_alg: key_agreement_alg,
kdf_alg: KeyDerivation::Hkdf {
hash_alg: Hash::Sha256,
},
}
.into(),
},
};
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_derive();
let derived_key_attributes = Attributes {
key_type: Type::RawData,
bits: 8,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: KeyDerivation::Hkdf {
hash_alg: Hash::Sha256,
}
.into(),
},
};
psa_crypto::init().unwrap();
let key_agreement_key =
key_management::import(key_agr_attributes, None, &PRIVATE_KEY_DATA).unwrap();
let my_key = key_management::import(attributes, None, &KEY_DATA).unwrap();
let operation = Operation {
inputs: Inputs::Hkdf {
hash_alg: Hash::Sha256,
salt: None,
secret: InputSecret::KeyAgreement {
alg: key_agreement_alg,
private_key: key_agreement_key,
peer_key: &PEER_PUBLIC_KEY,
},
info: Input::Key(my_key),
},
capacity: None,
};
let _new_key = key_derivation::output_key(operation, derived_key_attributes, None).unwrap();
}
psa-crypto-0.9.2/tests/mod.rs 0000644 0000000 0000000 00000017652 10461020230 0014237 0 ustar 0000000 0000000 // Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
#![allow(clippy::multiple_crate_versions)]
use psa_crypto::operations::key_management;
use psa_crypto::types::algorithm::{Algorithm, AsymmetricSignature, Hash};
use psa_crypto::types::key::{Attributes, EccFamily, Lifetime, Policy, Type, UsageFlags};
mod aead;
mod hash;
mod key_agreement;
#[test]
fn generate_integration_test() {
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_verify_message();
let attributes = Attributes {
lifetime: Lifetime::Persistent,
key_type: Type::RsaKeyPair,
bits: 1024,
policy: Policy {
usage_flags,
permitted_algorithms: Algorithm::AsymmetricSignature(
AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
},
),
},
};
let mut test_client = test_tools::TestClient::new();
// Ensure that a large number of keys can be generated
for key_index in 1..101u32 {
test_client.generate(attributes, Some(key_index));
}
}
#[test]
fn import_integration_test() {
const KEY_DATA: [u8; 140] = [
48, 129, 137, 2, 129, 129, 0, 153, 165, 220, 135, 89, 101, 254, 229, 28, 33, 138, 247, 20,
102, 253, 217, 247, 246, 142, 107, 51, 40, 179, 149, 45, 117, 254, 236, 161, 109, 16, 81,
135, 72, 112, 132, 150, 175, 128, 173, 182, 122, 227, 214, 196, 130, 54, 239, 93, 5, 203,
185, 233, 61, 159, 156, 7, 161, 87, 48, 234, 105, 161, 108, 215, 211, 150, 168, 156, 212,
6, 63, 81, 24, 101, 72, 160, 97, 243, 142, 86, 10, 160, 122, 8, 228, 178, 252, 35, 209,
222, 228, 16, 143, 99, 143, 146, 241, 186, 187, 22, 209, 86, 141, 24, 159, 12, 146, 44,
111, 254, 183, 54, 229, 109, 28, 39, 22, 141, 173, 85, 26, 58, 9, 128, 27, 57, 131, 2, 3,
1, 0, 1,
];
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_verify_hash().set_sign_hash();
let attributes = Attributes {
lifetime: Lifetime::Persistent,
key_type: Type::RsaPublicKey,
bits: 1024,
policy: Policy {
usage_flags,
permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
}
.into(),
},
};
let mut test_client = test_tools::TestClient::new();
// Ensure that a large number of keys can be imported
for key_index in 101..201u32 {
test_client.import(attributes, key_index, &KEY_DATA);
}
}
#[test]
fn export_key_pair_test() {
const PRIVATE_KEY: &str = "MIICWwIBAAKBgQCd+EKeRmZCKLmg7LasWqpKA9/01linY75ujilf6v/Kb8UP9r/E\
cO75Pvi2YPnYhBadmVOVxMOqS2zmKm1a9VTegT8dN9Unf2s2KbKrKXupaQTXcrGG\
SB/BmHeWeiqidEMw7i9ysjHK4KEuacmYmZpvKAnNWMyvQgjGgGNpsNzqawIDAQAB\
AoGAcHlAxXyOdnCUqpWgAtuS/5v+q06qVJRaFFE3+ElT0oj+ID2pkG5wWBqT7xbh\
DV4O1CtFLg+o2OlXIhH3RpoC0D0x3qfvDpY5nJUUhP/w7mtGOwvB08xhXBN2M9fk\
PNqGdrzisvxTry3rp9qDduZlv1rTCsx8+ww3iI4Q0coD4fECQQD4KAMgIS7Vu+Vm\
zQmJfVfzYCVdr4X3Z/JOEexb3eu9p1Qj904sLu9Ds5NO7atT+qtDYVxgH5kQIrKk\
mFNAx3NdAkEAovZ+DaorhkDiL/gFVzwoShyc1A6AWkH791sDlns2ETZ1WwE/ccYu\
uJill/5XA9RKw6whUDzzNTsv7bFkCruAZwJARP5y6ALxz5DfFfbZuPU1d7/6g5Ki\
b4fh8VzAV0ZbHa6hESLYBCbEdRE/WolvwfiGl0RBd6QxXTAYdPS46ODLLQJARrz4\
urXDbuN7S5c9ukBCvOjuqp4g2Q0LcrPvOsMBFTeueXJxN9HvNfIM741X+DGOwqFV\
VJ8gc1rd0y/NXVtGwQJAc2w23nTmZ/olcMVRia1+AFsELcCnD+JqaJ2AEF1Ng6Ix\
V/X2l32v6t3B57sw/8ce3LCheEdqLHlSOpQiaD7Qfw==";
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_sign_hash().set_verify_hash().set_export();
let attributes = Attributes {
key_type: Type::RsaKeyPair,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
}
.into(),
},
};
psa_crypto::init().unwrap();
let mut test_client = test_tools::TestClient::new();
let decoded_pk = base64::decode(PRIVATE_KEY).unwrap();
let id = test_client.import(attributes, 201, &decoded_pk);
let buffer_size = attributes.export_key_output_size().unwrap();
let mut data = vec![0; buffer_size];
let size = test_client.export_key_pair(id, &mut data).unwrap();
data.resize(size, 0);
assert_eq!(decoded_pk, data);
}
#[test]
fn copy_key_success() {
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_export().set_copy();
let attributes = Attributes {
key_type: Type::RsaKeyPair,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: Algorithm::None,
},
};
let mut test_client = test_tools::TestClient::new();
let key_id = test_client.generate(attributes, None);
let copied_key_id = test_client.copy_key(key_id, attributes, None);
let mut original_key_material = vec![0; attributes.export_key_output_size().unwrap()];
let mut copied_key_material = vec![0; attributes.export_key_output_size().unwrap()];
test_client
.export_key_pair(key_id, &mut original_key_material)
.unwrap();
test_client
.export_key_pair(copied_key_id, &mut copied_key_material)
.unwrap();
assert_eq!(original_key_material, copied_key_material);
}
#[test]
fn copy_key_incompatible_copy_attrs() {
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_copy().set_export();
let attributes = Attributes {
key_type: Type::RsaKeyPair,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: Algorithm::None,
},
};
let mut usage_flags: UsageFlags = Default::default();
usage_flags.set_copy().set_export();
let incompatible_copy_attrs = Attributes {
key_type: Type::EccKeyPair {
curve_family: EccFamily::SecpR1,
},
bits: 448,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags,
permitted_algorithms: Algorithm::None,
},
};
let mut test_client = test_tools::TestClient::new();
let key_id = test_client.generate(attributes, None);
let _copied_key_id = key_management::copy(key_id, incompatible_copy_attrs, None).unwrap_err();
}
mod test_tools {
use psa_crypto::operations::key_management;
use psa_crypto::types::key::{Attributes, Id};
use psa_crypto::types::status::Result;
pub struct TestClient {
keys: Vec,
}
impl TestClient {
pub fn new() -> Self {
psa_crypto::init().unwrap();
TestClient { keys: Vec::new() }
}
pub fn generate(&mut self, attributes: Attributes, key_id: Option) -> Id {
let id = key_management::generate(attributes, key_id).unwrap();
self.keys.push(id);
id
}
pub fn import(&mut self, attributes: Attributes, key_id: u32, key_data: &[u8]) -> Id {
let id = key_management::import(attributes, Some(key_id), key_data).unwrap();
self.keys.push(id);
id
}
pub fn export_key_pair(&mut self, key_id: Id, key_data: &mut [u8]) -> Result {
key_management::export(key_id, key_data)
}
pub fn copy_key(
&mut self,
key_id: Id,
attributes: Attributes,
id_for_new_persistent_key: Option,
) -> Id {
let id = key_management::copy(key_id, attributes, id_for_new_persistent_key).unwrap();
self.keys.push(id);
id
}
}
impl Drop for TestClient {
fn drop(&mut self) {
for key in self.keys.clone() {
unsafe { key_management::destroy(key) }.unwrap();
}
}
}
}