Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally implement Zeroize on ArrayVec/ArrayString #240

Merged
merged 2 commits into from Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -22,12 +22,13 @@ jobs:
experimental: false
- rust: stable
features:
bench: true
experimental: false
- rust: beta
features: serde
experimental: false
- rust: nightly
features: serde
features: serde, zeroize
experimental: false

steps:
Expand Down Expand Up @@ -57,4 +58,4 @@ jobs:
rustup override set nightly
cargo miri setup
- name: Test with Miri
run: cargo miri test
run: cargo miri test --all-features
5 changes: 5 additions & 0 deletions Cargo.toml
Expand Up @@ -19,6 +19,11 @@ version = "1.0"
optional = true
default-features = false

[dependencies.zeroize]
version = "1.4"
optional = true
default-features = false

[dev-dependencies.serde_test]
version = "1.0"

Expand Down
24 changes: 24 additions & 0 deletions src/array_string.rs
Expand Up @@ -647,3 +647,27 @@ impl<'a, const CAP: usize> TryFrom<fmt::Arguments<'a>> for ArrayString<CAP>
Ok(v)
}
}

#[cfg(feature = "zeroize")]
/// "Best efforts" zeroing of the `ArrayString`'s buffer when the `zeroize` feature is enabled.
///
/// The length is set to 0, and the buffer is dropped and zeroized.
/// Cannot ensure that previous moves of the `ArrayString` did not leave values on the stack.
///
/// ```
/// use arrayvec::ArrayString;
/// use zeroize::Zeroize;
/// let mut string = ArrayString::<6>::from("foobar").unwrap();
/// string.zeroize();
/// assert_eq!(string.len(), 0);
/// unsafe { string.set_len(string.capacity()) };
/// assert_eq!(&*string, "\0\0\0\0\0\0");
/// ```
impl<const CAP: usize> zeroize::Zeroize for ArrayString<CAP> {
fn zeroize(&mut self) {
// There are no elements to drop
self.clear();
// Zeroize the backing array.
self.xs.zeroize();
}
}
26 changes: 26 additions & 0 deletions src/arrayvec.rs
Expand Up @@ -848,6 +848,32 @@ impl<T, const CAP: usize> IntoIterator for ArrayVec<T, CAP> {
}


#[cfg(feature = "zeroize")]
/// "Best efforts" zeroing of the `ArrayVec`'s buffer when the `zeroize` feature is enabled.
///
/// The length is set to 0, and the buffer is dropped and zeroized.
/// Cannot ensure that previous moves of the `ArrayVec` did not leave values on the stack.
///
/// ```
/// use arrayvec::ArrayVec;
/// use zeroize::Zeroize;
/// let mut array = ArrayVec::from([1, 2, 3]);
/// array.zeroize();
/// assert_eq!(array.len(), 0);
/// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) };
/// assert_eq!(data, [0, 0, 0]);
/// ```
impl<Z: zeroize::Zeroize, const CAP: usize> zeroize::Zeroize for ArrayVec<Z, CAP> {
fn zeroize(&mut self) {
// Zeroize all the contained elements.
self.iter_mut().zeroize();
// Drop all the elements and set the length to 0.
self.clear();
// Zeroize the backing array.
self.xs.zeroize();
}
}

/// By-value iterator for `ArrayVec`.
pub struct IntoIter<T, const CAP: usize> {
index: usize,
Expand Down