All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Rust abstractions for Crypto API
@ 2023-07-10 10:22 FUJITA Tomonori
  2023-07-10 10:22 ` [PATCH v2 1/3] rust: crypto abstractions for synchronous message digest API FUJITA Tomonori
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: FUJITA Tomonori @ 2023-07-10 10:22 UTC (permalink / raw)
  To: rust-for-linux, linux-crypto; +Cc: alex.gaynor, herbert, ebiggers, benno.lossin

This patchset adds minimum Rust abstractions for Crypto API; message
digest and random number generator.

I'm trying to upstream network and crypto abstractions separately so
v2 has only crypto stuff.

Changes since v1 [1]:
- ShashDesc::new() returns the initialized object.
- checks the length of buffer.
- fix a compile error without CONFIG_CRYPTO.
- adds RNG support.
- drops network code.
- updates the CRYPTO API entry.

[1] https://lore.kernel.org/netdev/010101881db036fb-2fb6981d-e0ef-4ad1-83c3-54d64b6d93b3-000000@us-west-2.amazonses.com/T/

FUJITA Tomonori (3):
  rust: crypto abstractions for synchronous message digest API
  rust: crypto abstractions for random number generator API
  MAINTAINERS: add Rust crypto abstractions files to the CRYPTO API
    entry

 MAINTAINERS                     |   2 +
 rust/bindings/bindings_helper.h |   2 +
 rust/helpers.c                  |  38 ++++++++++
 rust/kernel/crypto.rs           |   6 ++
 rust/kernel/crypto/hash.rs      | 128 ++++++++++++++++++++++++++++++++
 rust/kernel/crypto/rng.rs       | 101 +++++++++++++++++++++++++
 rust/kernel/lib.rs              |   2 +
 7 files changed, 279 insertions(+)
 create mode 100644 rust/kernel/crypto.rs
 create mode 100644 rust/kernel/crypto/hash.rs
 create mode 100644 rust/kernel/crypto/rng.rs

-- 
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/3] rust: crypto abstractions for synchronous message digest API
  2023-07-10 10:22 [PATCH v2 0/3] Rust abstractions for Crypto API FUJITA Tomonori
@ 2023-07-10 10:22 ` FUJITA Tomonori
  2023-07-14 16:19   ` Benno Lossin
  2023-07-10 10:22 ` [PATCH v2 2/3] rust: crypto abstractions for random number generator API FUJITA Tomonori
  2023-07-10 10:22 ` [PATCH v2 3/3] MAINTAINERS: add Rust crypto abstractions files to the CRYPTO API entry FUJITA Tomonori
  2 siblings, 1 reply; 6+ messages in thread
From: FUJITA Tomonori @ 2023-07-10 10:22 UTC (permalink / raw)
  To: rust-for-linux, linux-crypto; +Cc: alex.gaynor, herbert, ebiggers, benno.lossin

This patch adds basic abstractions for synchronous message digest API,
wrapping crypto_shash and shash_desc structures.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers.c                  |  26 +++++++
 rust/kernel/crypto.rs           |   5 ++
 rust/kernel/crypto/hash.rs      | 128 ++++++++++++++++++++++++++++++++
 rust/kernel/lib.rs              |   2 +
 5 files changed, 162 insertions(+)
 create mode 100644 rust/kernel/crypto.rs
 create mode 100644 rust/kernel/crypto/hash.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 3e601ce2548d..2f198c6d5de5 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -6,6 +6,7 @@
  * Sorted alphabetically.
  */
 
+#include <crypto/hash.h>
 #include <linux/errname.h>
 #include <linux/slab.h>
 #include <linux/refcount.h>
diff --git a/rust/helpers.c b/rust/helpers.c
index bb594da56137..7966902ed8eb 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -18,6 +18,7 @@
  * accidentally exposed.
  */
 
+#include <crypto/hash.h>
 #include <linux/bug.h>
 #include <linux/build_bug.h>
 #include <linux/err.h>
@@ -28,6 +29,31 @@
 #include <linux/sched/signal.h>
 #include <linux/wait.h>
 
+#ifdef CONFIG_CRYPTO
+void rust_helper_crypto_free_shash(struct crypto_shash *tfm)
+{
+	crypto_free_shash(tfm);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash);
+
+unsigned int rust_helper_crypto_shash_digestsize(struct crypto_shash *tfm)
+{
+    return crypto_shash_digestsize(tfm);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_digestsize);
+
+unsigned int rust_helper_crypto_shash_descsize(struct crypto_shash *tfm)
+{
+    return crypto_shash_descsize(tfm);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_descsize);
+
+int rust_helper_crypto_shash_init(struct shash_desc *desc) {
+	return crypto_shash_init(desc);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_init);
+#endif
+
 __noreturn void rust_helper_BUG(void)
 {
 	BUG();
diff --git a/rust/kernel/crypto.rs b/rust/kernel/crypto.rs
new file mode 100644
index 000000000000..f80dd7bd3381
--- /dev/null
+++ b/rust/kernel/crypto.rs
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Cryptography.
+
+pub mod hash;
diff --git a/rust/kernel/crypto/hash.rs b/rust/kernel/crypto/hash.rs
new file mode 100644
index 000000000000..cdbc8e70e8f5
--- /dev/null
+++ b/rust/kernel/crypto/hash.rs
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Cryptographic Hash operations.
+//!
+//! C headers: [`include/crypto/hash.h`](../../../../include/crypto/hash.h)
+
+use crate::{
+    error::{
+        code::{EINVAL, ENOMEM},
+        from_err_ptr, to_result, Result,
+    },
+    str::CStr,
+};
+use alloc::alloc::{alloc, dealloc};
+use core::alloc::Layout;
+
+/// Corresponds to the kernel's `struct crypto_shash`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Shash(*mut bindings::crypto_shash);
+
+impl Drop for Shash {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the pointer is valid.
+        unsafe { bindings::crypto_free_shash(self.0) }
+    }
+}
+
+impl Shash {
+    /// Creates a [`Shash`] object for a message digest handle.
+    pub fn new(name: &CStr, t: u32, mask: u32) -> Result<Shash> {
+        // SAFETY: There are no safety requirements for this FFI call.
+        let ptr =
+            unsafe { from_err_ptr(bindings::crypto_alloc_shash(name.as_char_ptr(), t, mask)) }?;
+        // INVARIANT: `ptr` is valid and non-null since `crypto_alloc_shash`
+        // returned a valid pointer which was null-checked.
+        Ok(Self(ptr))
+    }
+
+    /// Sets optional key used by the hashing algorithm.
+    pub fn setkey(&mut self, data: &[u8]) -> Result {
+        // SAFETY: The type invariant guarantees that the pointer is valid.
+        to_result(unsafe {
+            bindings::crypto_shash_setkey(self.0, data.as_ptr(), data.len() as u32)
+        })
+    }
+
+    /// Returns the size of the result of the transformation.
+    pub fn digestsize(&self) -> u32 {
+        // SAFETY: The type invariant guarantees that the pointer is valid.
+        unsafe { bindings::crypto_shash_digestsize(self.0) }
+    }
+}
+
+/// Corresponds to the kernel's `struct shash_desc`.
+///
+/// # Invariants
+///
+/// The field `ptr` is valid.
+pub struct ShashDesc<'a> {
+    ptr: *mut bindings::shash_desc,
+    tfm: &'a Shash,
+    size: usize,
+}
+
+impl Drop for ShashDesc<'_> {
+    fn drop(&mut self) {
+        // SAFETY: The type invariant guarantees that the pointer is valid.
+        unsafe {
+            dealloc(
+                self.ptr.cast(),
+                Layout::from_size_align(self.size, 2).unwrap(),
+            );
+        }
+    }
+}
+
+impl<'a> ShashDesc<'a> {
+    /// Creates a [`ShashDesc`] object for a request data structure for message digest.
+    pub fn new(tfm: &'a Shash) -> Result<Self> {
+        // SAFETY: The type invariant guarantees that `tfm.0` pointer is valid.
+        let size = core::mem::size_of::<bindings::shash_desc>()
+            + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize;
+        let layout = Layout::from_size_align(size, 2)?;
+        // SAFETY: It's safe because layout has non-zero size.
+        let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc;
+        if ptr.is_null() {
+            return Err(ENOMEM);
+        }
+        // INVARIANT: `ptr` is valid and non-null since `alloc`
+        // returned a valid pointer which was null-checked.
+        let mut desc = ShashDesc { ptr, tfm, size };
+        // SAFETY: `desc.ptr` is valid and non-null since `alloc`
+        // returned a valid pointer which was null-checked.
+        // Additionally, The type invariant guarantees that `tfm.0` is valid.
+        unsafe { (*desc.ptr).tfm = desc.tfm.0 };
+        desc.reset()?;
+        Ok(desc)
+    }
+
+    /// Re-initializes message digest.
+    pub fn reset(&mut self) -> Result {
+        // SAFETY: The type invariant guarantees that the pointer is valid.
+        to_result(unsafe { bindings::crypto_shash_init(self.ptr) })
+    }
+
+    /// Adds data to message digest for processing.
+    pub fn update(&mut self, data: &[u8]) -> Result {
+        if data.len() > u32::MAX as usize {
+            return Err(EINVAL);
+        }
+        // SAFETY: The type invariant guarantees that the pointer is valid.
+        to_result(unsafe {
+            bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32)
+        })
+    }
+
+    /// Calculates message digest.
+    pub fn finalize(&mut self, output: &mut [u8]) -> Result {
+        if self.tfm.digestsize() as usize > output.len() {
+            return Err(EINVAL);
+        }
+        // SAFETY: The type invariant guarantees that the pointer is valid.
+        to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) })
+    }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 85b261209977..3cb8bd8a17d9 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -31,6 +31,8 @@
 #[cfg(not(testlib))]
 mod allocator;
 mod build_assert;
+#[cfg(CONFIG_CRYPTO)]
+pub mod crypto;
 pub mod error;
 pub mod init;
 pub mod ioctl;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/3] rust: crypto abstractions for random number generator API
  2023-07-10 10:22 [PATCH v2 0/3] Rust abstractions for Crypto API FUJITA Tomonori
  2023-07-10 10:22 ` [PATCH v2 1/3] rust: crypto abstractions for synchronous message digest API FUJITA Tomonori
@ 2023-07-10 10:22 ` FUJITA Tomonori
  2023-07-14 16:20   ` Benno Lossin
  2023-07-10 10:22 ` [PATCH v2 3/3] MAINTAINERS: add Rust crypto abstractions files to the CRYPTO API entry FUJITA Tomonori
  2 siblings, 1 reply; 6+ messages in thread
From: FUJITA Tomonori @ 2023-07-10 10:22 UTC (permalink / raw)
  To: rust-for-linux, linux-crypto; +Cc: alex.gaynor, herbert, ebiggers, benno.lossin

This patch adds basic abstractions for random number generator API,
wrapping crypto_rng structure.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers.c                  |  12 ++++
 rust/kernel/crypto.rs           |   1 +
 rust/kernel/crypto/rng.rs       | 101 ++++++++++++++++++++++++++++++++
 4 files changed, 115 insertions(+)
 create mode 100644 rust/kernel/crypto/rng.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 2f198c6d5de5..089ac38c6461 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -7,6 +7,7 @@
  */
 
 #include <crypto/hash.h>
+#include <crypto/rng.h>
 #include <linux/errname.h>
 #include <linux/slab.h>
 #include <linux/refcount.h>
diff --git a/rust/helpers.c b/rust/helpers.c
index 7966902ed8eb..e4dcd611738f 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -19,6 +19,7 @@
  */
 
 #include <crypto/hash.h>
+#include <crypto/rng.h>
 #include <linux/bug.h>
 #include <linux/build_bug.h>
 #include <linux/err.h>
@@ -52,6 +53,17 @@ int rust_helper_crypto_shash_init(struct shash_desc *desc) {
 	return crypto_shash_init(desc);
 }
 EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_init);
+
+void rust_helper_crypto_free_rng(struct crypto_rng *tfm) {
+	crypto_free_rng(tfm);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_free_rng);
+
+int rust_helper_crypto_rng_generate(struct crypto_rng *tfm, const u8 *src,
+	unsigned int slen, u8 *dst, unsigned int dlen) {
+	return crypto_rng_generate(tfm, src, slen, dst, dlen);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_rng_generate);
 #endif
 
 __noreturn void rust_helper_BUG(void)
diff --git a/rust/kernel/crypto.rs b/rust/kernel/crypto.rs
index f80dd7bd3381..a1995e6c85d4 100644
--- a/rust/kernel/crypto.rs
+++ b/rust/kernel/crypto.rs
@@ -3,3 +3,4 @@
 //! Cryptography.
 
 pub mod hash;
+pub mod rng;
diff --git a/rust/kernel/crypto/rng.rs b/rust/kernel/crypto/rng.rs
new file mode 100644
index 000000000000..683f5ee464ce
--- /dev/null
+++ b/rust/kernel/crypto/rng.rs
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Random number generator.
+//!
+//! C headers: [`include/crypto/rng.h`](../../../../include/crypto/rng.h)
+
+use crate::{
+    error::{code::EINVAL, from_err_ptr, to_result, Result},
+    str::CStr,
+};
+
+/// Type of Random number generator.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+enum RngType {
+    /// Uses `crypto_default_rng`
+    // We don't need to keep an pointer for the default but simpler.
+    Default(*mut bindings::crypto_rng),
+
+    /// Allocated via `crypto_alloc_rng.
+    Allocated(*mut bindings::crypto_rng),
+}
+
+/// Corresponds to the kernel's `struct crypto_rng`.
+pub struct Rng(RngType);
+
+impl Drop for Rng {
+    fn drop(&mut self) {
+        match self.0 {
+            RngType::Default(_) => {
+                // SAFETY: it's safe because `crypto_get_default_rng()` was called during
+                // the initialization.
+                unsafe {
+                    bindings::crypto_put_default_rng();
+                }
+            }
+            RngType::Allocated(ptr) => {
+                // SAFETY: The type invariants of `RngType` guarantees that the pointer is valid.
+                unsafe { bindings::crypto_free_rng(ptr) };
+            }
+        }
+    }
+}
+
+impl Rng {
+    /// Creates a [`Rng`] instance.
+    pub fn new(name: &CStr, t: u32, mask: u32) -> Result<Self> {
+        // SAFETY: There are no safety requirements for this FFI call.
+        let ptr = unsafe { from_err_ptr(bindings::crypto_alloc_rng(name.as_char_ptr(), t, mask)) }?;
+        // INVARIANT: `ptr` is valid and non-null since `crypto_alloc_rng`
+        // returned a valid pointer which was null-checked.
+        Ok(Self(RngType::Allocated(ptr)))
+    }
+
+    /// Creates a [`Rng`] instance with a default algorithm.
+    pub fn new_with_default() -> Result<Self> {
+        // SAFETY: There are no safety requirements for this FFI call.
+        to_result(unsafe { bindings::crypto_get_default_rng() })?;
+        // INVARIANT: The C API guarantees that `crypto_default_rng` is valid until
+        // `crypto_put_default_rng` is called.
+        Ok(Self(RngType::Default(unsafe {
+            bindings::crypto_default_rng
+        })))
+    }
+
+    /// Get a random number.
+    pub fn generate(&mut self, src: &[u8], dst: &mut [u8]) -> Result {
+        if src.len() > u32::MAX as usize || dst.len() > u32::MAX as usize {
+            return Err(EINVAL);
+        }
+        let ptr = match self.0 {
+            RngType::Default(ptr) => ptr,
+            RngType::Allocated(ptr) => ptr,
+        };
+        // SAFETY: The type invariants of `RngType' guarantees that the pointer is valid.
+        to_result(unsafe {
+            bindings::crypto_rng_generate(
+                ptr,
+                src.as_ptr(),
+                src.len() as u32,
+                dst.as_mut_ptr(),
+                dst.len() as u32,
+            )
+        })
+    }
+
+    /// Re-initializes the [`Rng`] instance.
+    pub fn reset(&mut self, seed: &[u8]) -> Result {
+        if seed.len() > u32::MAX as usize {
+            return Err(EINVAL);
+        }
+        let ptr = match self.0 {
+            RngType::Default(ptr) => ptr,
+            RngType::Allocated(ptr) => ptr,
+        };
+        // SAFETY: The type invariants of `RngType' guarantees that the pointer is valid.
+        to_result(unsafe { bindings::crypto_rng_reset(ptr, seed.as_ptr(), seed.len() as u32) })
+    }
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] MAINTAINERS: add Rust crypto abstractions files to the CRYPTO API entry
  2023-07-10 10:22 [PATCH v2 0/3] Rust abstractions for Crypto API FUJITA Tomonori
  2023-07-10 10:22 ` [PATCH v2 1/3] rust: crypto abstractions for synchronous message digest API FUJITA Tomonori
  2023-07-10 10:22 ` [PATCH v2 2/3] rust: crypto abstractions for random number generator API FUJITA Tomonori
@ 2023-07-10 10:22 ` FUJITA Tomonori
  2 siblings, 0 replies; 6+ messages in thread
From: FUJITA Tomonori @ 2023-07-10 10:22 UTC (permalink / raw)
  To: rust-for-linux, linux-crypto; +Cc: alex.gaynor, herbert, ebiggers, benno.lossin

The files are placed at rust/kernel/ directory for now but the files
are likely to be moved to crypto/ directory if things go well.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 250518fc70ff..3dd33850ff7e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5446,6 +5446,8 @@ F:	drivers/crypto/
 F:	include/crypto/
 F:	include/linux/crypto*
 F:	lib/crypto/
+F:	rust/kernel/crypto.rs
+F:	rust/kernel/crypto/
 
 CRYPTOGRAPHIC RANDOM NUMBER GENERATOR
 M:	Neil Horman <nhorman@tuxdriver.com>
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 1/3] rust: crypto abstractions for synchronous message digest API
  2023-07-10 10:22 ` [PATCH v2 1/3] rust: crypto abstractions for synchronous message digest API FUJITA Tomonori
@ 2023-07-14 16:19   ` Benno Lossin
  0 siblings, 0 replies; 6+ messages in thread
From: Benno Lossin @ 2023-07-14 16:19 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: rust-for-linux, linux-crypto, alex.gaynor, herbert, ebiggers

> This patch adds basic abstractions for synchronous message digest API,
> wrapping crypto_shash and shash_desc structures.
> 
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
>  rust/bindings/bindings_helper.h |   1 +
>  rust/helpers.c                  |  26 +++++++
>  rust/kernel/crypto.rs           |   5 ++
>  rust/kernel/crypto/hash.rs      | 128 ++++++++++++++++++++++++++++++++
>  rust/kernel/lib.rs              |   2 +
>  5 files changed, 162 insertions(+)
>  create mode 100644 rust/kernel/crypto.rs
>  create mode 100644 rust/kernel/crypto/hash.rs
> 
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 3e601ce2548d..2f198c6d5de5 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -6,6 +6,7 @@
>   * Sorted alphabetically.
>   */
> 
> +#include <crypto/hash.h>
>  #include <linux/errname.h>
>  #include <linux/slab.h>
>  #include <linux/refcount.h>
> diff --git a/rust/helpers.c b/rust/helpers.c
> index bb594da56137..7966902ed8eb 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -18,6 +18,7 @@
>   * accidentally exposed.
>   */
> 
> +#include <crypto/hash.h>
>  #include <linux/bug.h>
>  #include <linux/build_bug.h>
>  #include <linux/err.h>
> @@ -28,6 +29,31 @@
>  #include <linux/sched/signal.h>
>  #include <linux/wait.h>
> 
> +#ifdef CONFIG_CRYPTO
> +void rust_helper_crypto_free_shash(struct crypto_shash *tfm)
> +{
> +	crypto_free_shash(tfm);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash);
> +
> +unsigned int rust_helper_crypto_shash_digestsize(struct crypto_shash *tfm)
> +{
> +    return crypto_shash_digestsize(tfm);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_digestsize);
> +
> +unsigned int rust_helper_crypto_shash_descsize(struct crypto_shash *tfm)
> +{
> +    return crypto_shash_descsize(tfm);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_descsize);
> +
> +int rust_helper_crypto_shash_init(struct shash_desc *desc) {
> +	return crypto_shash_init(desc);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_init);
> +#endif
> +
>  __noreturn void rust_helper_BUG(void)
>  {
>  	BUG();
> diff --git a/rust/kernel/crypto.rs b/rust/kernel/crypto.rs
> new file mode 100644
> index 000000000000..f80dd7bd3381
> --- /dev/null
> +++ b/rust/kernel/crypto.rs
> @@ -0,0 +1,5 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Cryptography.
> +
> +pub mod hash;
> diff --git a/rust/kernel/crypto/hash.rs b/rust/kernel/crypto/hash.rs
> new file mode 100644
> index 000000000000..cdbc8e70e8f5
> --- /dev/null
> +++ b/rust/kernel/crypto/hash.rs
> @@ -0,0 +1,128 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Cryptographic Hash operations.
> +//!
> +//! C headers: [`include/crypto/hash.h`](../../../../include/crypto/hash.h)
> +
> +use crate::{
> +    error::{
> +        code::{EINVAL, ENOMEM},
> +        from_err_ptr, to_result, Result,
> +    },
> +    str::CStr,
> +};
> +use alloc::alloc::{alloc, dealloc};
> +use core::alloc::Layout;
> +
> +/// Corresponds to the kernel's `struct crypto_shash`.
> +///
> +/// # Invariants
> +///
> +/// The pointer is valid.
> +pub struct Shash(*mut bindings::crypto_shash);
> +
> +impl Drop for Shash {
> +    fn drop(&mut self) {
> +        // SAFETY: The type invariant guarantees that the pointer is valid.
> +        unsafe { bindings::crypto_free_shash(self.0) }
> +    }
> +}
> +
> +impl Shash {
> +    /// Creates a [`Shash`] object for a message digest handle.
> +    pub fn new(name: &CStr, t: u32, mask: u32) -> Result<Shash> {
> +        // SAFETY: There are no safety requirements for this FFI call.
> +        let ptr =
> +            unsafe { from_err_ptr(bindings::crypto_alloc_shash(name.as_char_ptr(), t, mask)) }?;
> +        // INVARIANT: `ptr` is valid and non-null since `crypto_alloc_shash`
> +        // returned a valid pointer which was null-checked.
> +        Ok(Self(ptr))
> +    }
> +
> +    /// Sets optional key used by the hashing algorithm.
> +    pub fn setkey(&mut self, data: &[u8]) -> Result {
> +        // SAFETY: The type invariant guarantees that the pointer is valid.
> +        to_result(unsafe {
> +            bindings::crypto_shash_setkey(self.0, data.as_ptr(), data.len() as u32)
> +        })
> +    }
> +
> +    /// Returns the size of the result of the transformation.
> +    pub fn digestsize(&self) -> u32 {
> +        // SAFETY: The type invariant guarantees that the pointer is valid.
> +        unsafe { bindings::crypto_shash_digestsize(self.0) }
> +    }
> +}
> +
> +/// Corresponds to the kernel's `struct shash_desc`.
> +///
> +/// # Invariants
> +///
> +/// The field `ptr` is valid.
> +pub struct ShashDesc<'a> {
> +    ptr: *mut bindings::shash_desc,
> +    tfm: &'a Shash,
> +    size: usize,
> +}
> +
> +impl Drop for ShashDesc<'_> {
> +    fn drop(&mut self) {
> +        // SAFETY: The type invariant guarantees that the pointer is valid.
> +        unsafe {
> +            dealloc(
> +                self.ptr.cast(),
> +                Layout::from_size_align(self.size, 2).unwrap(),
> +            );
> +        }
> +    }
> +}
> +
> +impl<'a> ShashDesc<'a> {
> +    /// Creates a [`ShashDesc`] object for a request data structure for message digest.
> +    pub fn new(tfm: &'a Shash) -> Result<Self> {
> +        // SAFETY: The type invariant guarantees that `tfm.0` pointer is valid.
> +        let size = core::mem::size_of::<bindings::shash_desc>()
> +            + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize;
> +        let layout = Layout::from_size_align(size, 2)?;

I still do not like this arbitrary `2` constant as the alignment. Why is
this correct? It should be explained in the code. Otherwise use a
different way to compute the layout via `Layout::new()` and/or
`Layout::repeat`/`Layout::extend` etc.

--
Cheers,
Benno

> +        // SAFETY: It's safe because layout has non-zero size.
> +        let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc;
> +        if ptr.is_null() {
> +            return Err(ENOMEM);
> +        }
> +        // INVARIANT: `ptr` is valid and non-null since `alloc`
> +        // returned a valid pointer which was null-checked.
> +        let mut desc = ShashDesc { ptr, tfm, size };
> +        // SAFETY: `desc.ptr` is valid and non-null since `alloc`
> +        // returned a valid pointer which was null-checked.
> +        // Additionally, The type invariant guarantees that `tfm.0` is valid.
> +        unsafe { (*desc.ptr).tfm = desc.tfm.0 };
> +        desc.reset()?;
> +        Ok(desc)
> +    }
> +
> +    /// Re-initializes message digest.
> +    pub fn reset(&mut self) -> Result {
> +        // SAFETY: The type invariant guarantees that the pointer is valid.
> +        to_result(unsafe { bindings::crypto_shash_init(self.ptr) })
> +    }
> +
> +    /// Adds data to message digest for processing.
> +    pub fn update(&mut self, data: &[u8]) -> Result {
> +        if data.len() > u32::MAX as usize {
> +            return Err(EINVAL);
> +        }
> +        // SAFETY: The type invariant guarantees that the pointer is valid.
> +        to_result(unsafe {
> +            bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32)
> +        })
> +    }
> +
> +    /// Calculates message digest.
> +    pub fn finalize(&mut self, output: &mut [u8]) -> Result {
> +        if self.tfm.digestsize() as usize > output.len() {
> +            return Err(EINVAL);
> +        }
> +        // SAFETY: The type invariant guarantees that the pointer is valid.
> +        to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) })
> +    }
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 85b261209977..3cb8bd8a17d9 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -31,6 +31,8 @@
>  #[cfg(not(testlib))]
>  mod allocator;
>  mod build_assert;
> +#[cfg(CONFIG_CRYPTO)]
> +pub mod crypto;
>  pub mod error;
>  pub mod init;
>  pub mod ioctl;
> --
> 2.34.1
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 2/3] rust: crypto abstractions for random number generator API
  2023-07-10 10:22 ` [PATCH v2 2/3] rust: crypto abstractions for random number generator API FUJITA Tomonori
@ 2023-07-14 16:20   ` Benno Lossin
  0 siblings, 0 replies; 6+ messages in thread
From: Benno Lossin @ 2023-07-14 16:20 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: rust-for-linux, linux-crypto, alex.gaynor, herbert, ebiggers

> This patch adds basic abstractions for random number generator API,
> wrapping crypto_rng structure.
> 
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
>  rust/bindings/bindings_helper.h |   1 +
>  rust/helpers.c                  |  12 ++++
>  rust/kernel/crypto.rs           |   1 +
>  rust/kernel/crypto/rng.rs       | 101 ++++++++++++++++++++++++++++++++
>  4 files changed, 115 insertions(+)
>  create mode 100644 rust/kernel/crypto/rng.rs
> 
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 2f198c6d5de5..089ac38c6461 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -7,6 +7,7 @@
>   */
> 
>  #include <crypto/hash.h>
> +#include <crypto/rng.h>
>  #include <linux/errname.h>
>  #include <linux/slab.h>
>  #include <linux/refcount.h>
> diff --git a/rust/helpers.c b/rust/helpers.c
> index 7966902ed8eb..e4dcd611738f 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -19,6 +19,7 @@
>   */
> 
>  #include <crypto/hash.h>
> +#include <crypto/rng.h>
>  #include <linux/bug.h>
>  #include <linux/build_bug.h>
>  #include <linux/err.h>
> @@ -52,6 +53,17 @@ int rust_helper_crypto_shash_init(struct shash_desc *desc) {
>  	return crypto_shash_init(desc);
>  }
>  EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_init);
> +
> +void rust_helper_crypto_free_rng(struct crypto_rng *tfm) {
> +	crypto_free_rng(tfm);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_crypto_free_rng);
> +
> +int rust_helper_crypto_rng_generate(struct crypto_rng *tfm, const u8 *src,
> +	unsigned int slen, u8 *dst, unsigned int dlen) {
> +	return crypto_rng_generate(tfm, src, slen, dst, dlen);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_crypto_rng_generate);
>  #endif
> 
>  __noreturn void rust_helper_BUG(void)
> diff --git a/rust/kernel/crypto.rs b/rust/kernel/crypto.rs
> index f80dd7bd3381..a1995e6c85d4 100644
> --- a/rust/kernel/crypto.rs
> +++ b/rust/kernel/crypto.rs
> @@ -3,3 +3,4 @@
>  //! Cryptography.
> 
>  pub mod hash;
> +pub mod rng;
> diff --git a/rust/kernel/crypto/rng.rs b/rust/kernel/crypto/rng.rs
> new file mode 100644
> index 000000000000..683f5ee464ce
> --- /dev/null
> +++ b/rust/kernel/crypto/rng.rs
> @@ -0,0 +1,101 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Random number generator.
> +//!
> +//! C headers: [`include/crypto/rng.h`](../../../../include/crypto/rng.h)
> +
> +use crate::{
> +    error::{code::EINVAL, from_err_ptr, to_result, Result},
> +    str::CStr,
> +};
> +
> +/// Type of Random number generator.
> +///
> +/// # Invariants
> +///
> +/// The pointer is valid.
> +enum RngType {
> +    /// Uses `crypto_default_rng`
> +    // We don't need to keep an pointer for the default but simpler.
> +    Default(*mut bindings::crypto_rng),
> +
> +    /// Allocated via `crypto_alloc_rng.
> +    Allocated(*mut bindings::crypto_rng),
> +}

You could also do this:
```
enum RngType {
    Default,
    Allocated(NonNull<bindings::crypto_rng>),
}
```

Assuming that `crypto_alloc_rng` never returns null.
Then this definition will the same size as a plain pointer.

> +
> +/// Corresponds to the kernel's `struct crypto_rng`.
> +pub struct Rng(RngType);
> +
> +impl Drop for Rng {
> +    fn drop(&mut self) {
> +        match self.0 {
> +            RngType::Default(_) => {
> +                // SAFETY: it's safe because `crypto_get_default_rng()` was called during
> +                // the initialization.
> +                unsafe {
> +                    bindings::crypto_put_default_rng();
> +                }
> +            }
> +            RngType::Allocated(ptr) => {
> +                // SAFETY: The type invariants of `RngType` guarantees that the pointer is valid.
> +                unsafe { bindings::crypto_free_rng(ptr) };
> +            }
> +        }
> +    }
> +}
> +
> +impl Rng {
> +    /// Creates a [`Rng`] instance.
> +    pub fn new(name: &CStr, t: u32, mask: u32) -> Result<Self> {
> +        // SAFETY: There are no safety requirements for this FFI call.
> +        let ptr = unsafe { from_err_ptr(bindings::crypto_alloc_rng(name.as_char_ptr(), t, mask)) }?;
> +        // INVARIANT: `ptr` is valid and non-null since `crypto_alloc_rng`
> +        // returned a valid pointer which was null-checked.
> +        Ok(Self(RngType::Allocated(ptr)))
> +    }
> +
> +    /// Creates a [`Rng`] instance with a default algorithm.
> +    pub fn new_with_default() -> Result<Self> {
> +        // SAFETY: There are no safety requirements for this FFI call.
> +        to_result(unsafe { bindings::crypto_get_default_rng() })?;
> +        // INVARIANT: The C API guarantees that `crypto_default_rng` is valid until
> +        // `crypto_put_default_rng` is called.
> +        Ok(Self(RngType::Default(unsafe {
> +            bindings::crypto_default_rng

You are accessing a `mut static`, this is `unsafe` (hence the need
for an `unsafe` block) and needs a safety comment, why is it safe to
access this mutable static? What synchronizes the access (is it not needed)?

> +        })))
> +    }
> +
> +    /// Get a random number.
> +    pub fn generate(&mut self, src: &[u8], dst: &mut [u8]) -> Result {
> +        if src.len() > u32::MAX as usize || dst.len() > u32::MAX as usize {
> +            return Err(EINVAL);
> +        }
> +        let ptr = match self.0 {
> +            RngType::Default(ptr) => ptr,
> +            RngType::Allocated(ptr) => ptr,
> +        };
> +        // SAFETY: The type invariants of `RngType' guarantees that the pointer is valid.
> +        to_result(unsafe {
> +            bindings::crypto_rng_generate(
> +                ptr,
> +                src.as_ptr(),
> +                src.len() as u32,
> +                dst.as_mut_ptr(),
> +                dst.len() as u32,
> +            )
> +        })
> +    }
> +
> +    /// Re-initializes the [`Rng`] instance.
> +    pub fn reset(&mut self, seed: &[u8]) -> Result {
> +        if seed.len() > u32::MAX as usize {
> +            return Err(EINVAL);
> +        }
> +        let ptr = match self.0 {
> +            RngType::Default(ptr) => ptr,
> +            RngType::Allocated(ptr) => ptr,
> +        };
> +        // SAFETY: The type invariants of `RngType' guarantees that the pointer is valid.
> +        to_result(unsafe { bindings::crypto_rng_reset(ptr, seed.as_ptr(), seed.len() as u32) })

If I read this correctly, then if I have to threads each with a `Default`
crypto rng, then one could be reset as the other is concurrently
generating some random numbers, right? This *should* be fine, but does
it make sense to do it? Or should there only be one thread accessing
the default crypto rng?

--
Cheers,
Benno

> +    }
> +}
> --
> 2.34.1
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-07-14 16:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-10 10:22 [PATCH v2 0/3] Rust abstractions for Crypto API FUJITA Tomonori
2023-07-10 10:22 ` [PATCH v2 1/3] rust: crypto abstractions for synchronous message digest API FUJITA Tomonori
2023-07-14 16:19   ` Benno Lossin
2023-07-10 10:22 ` [PATCH v2 2/3] rust: crypto abstractions for random number generator API FUJITA Tomonori
2023-07-14 16:20   ` Benno Lossin
2023-07-10 10:22 ` [PATCH v2 3/3] MAINTAINERS: add Rust crypto abstractions files to the CRYPTO API entry FUJITA Tomonori

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.