stouset / secrets Goto Github PK
View Code? Open in Web Editor NEWSecure storage for cryptographic secrets in Rust
License: Other
Secure storage for cryptographic secrets in Rust
License: Other
I am running secrets v0.11.1 and libsodium
$ apt-cache policy libsodium13
libsodium13:
Installed: 1.0.1-1
and even a small program like
extern crate secrets;
use secrets::SecretVec;
fn main() {
let secret = SecretVec::<u8>::zero(48);
}
segfaults with this backtrace:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7ba5844 in sodium_memcmp () from /usr/lib/x86_64-linux-gnu/libsodium.so.13
(gdb) where
#0 0x00007ffff7ba5844 in sodium_memcmp ()
from /usr/lib/x86_64-linux-gnu/libsodium.so.13
#1 0x00007ffff7ba5d0b in sodium_free ()
from /usr/lib/x86_64-linux-gnu/libsodium.so.13
#2 0x000055555555b2fd in secrets::sodium::free<u8> (ptr=0x7ffff7ff2fd0 "")
at /home/manuel/.cargo/registry/src/github.com-1ecc6299db9ec823/secrets-0.11.1/src/sodium.rs:51
#3 0x000055555555b0c5 in secrets::sec::{{impl}}::drop<u8> (self=0x7fffffffdf98)
at /home/manuel/.cargo/registry/src/github.com-1ecc6299db9ec823/secrets-0.11.1/src/sec.rs:40
#4 0x000055555555aae1 in drop::h68a5af34c64127be ()
#5 0x000055555555ab29 in drop::h8ecd862ad2c8e15b ()
#6 0x000055555555b491 in xx::main () at /tmp/xx/src/main.rs:7
#7 0x000055555556c747 in __rust_maybe_catch_panic ()
#8 0x0000555555563a02 in std::rt::lang_start::haaae1186de9de8cb ()
#9 0x000055555555b514 in main ()
PS: Oh, and I am running rustc 1.13.0-nightly (55bf6a4f8 2016-09-18)
Is there any reason that you explicitly search with pkg-config
for libsodium
?
This is done by libsodium-sys
with use-pkg-config
feature flag.
I believe this should be left to the user of the crate. Is it ok with you if I remove the link
in build.rs
and add use-pkg-config
feature flag that enables libsodium-sys/use-pkg-config
?
I'm having trouble compiling on OpenBSD 6.6 with libsodioum
(version 1.0.18) and rustc version 1.38.0.
I have tried the latest version both on crates.io and github.
I get the following output (tried both debug and release):
RUST_BACKTRACE=1 cargo build --release
Compiling secrets v0.12.1 (https://github.com/stouset/secrets#7c1d5ab8)
error: failed to run custom build command for `secrets v0.12.1 (https://github.com/stouset/secrets#7c1d5ab8)`
Caused by:
process didn't exit successfully: `/root/memsecstore/target/release/build/secrets-f5777c6962e6309d/build-script-build` (exit code: 101)
--- stdout
cargo:rerun-if-env-changed=COVERAGE
cargo:rerun-if-env-changed=PROFILE
cargo:rustc-cfg=profile="release"
cargo:rerun-if-env-changed=LIBSODIUM_NO_PKG_CONFIG
cargo:rerun-if-env-changed=PKG_CONFIG
cargo:rerun-if-env-changed=LIBSODIUM_STATIC
cargo:rerun-if-env-changed=LIBSODIUM_DYNAMIC
cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64-unknown-openbsd
cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64_unknown_openbsd
cargo:rerun-if-env-changed=HOST_PKG_CONFIG_PATH
cargo:rerun-if-env-changed=PKG_CONFIG_PATH
cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64-unknown-openbsd
cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64_unknown_openbsd
cargo:rerun-if-env-changed=HOST_PKG_CONFIG_LIBDIR
cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-openbsd
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_openbsd
cargo:rerun-if-env-changed=HOST_PKG_CONFIG_SYSROOT_DIR
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
cargo:rerun-if-env-changed=LIBSODIUM_STATIC
cargo:rerun-if-env-changed=LIBSODIUM_DYNAMIC
cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
cargo:rerun-if-env-changed=PKG_CONFIG
cargo:rerun-if-env-changed=LIBSODIUM_STATIC
cargo:rerun-if-env-changed=LIBSODIUM_DYNAMIC
cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64-unknown-openbsd
cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64_unknown_openbsd
cargo:rerun-if-env-changed=HOST_PKG_CONFIG_PATH
cargo:rerun-if-env-changed=PKG_CONFIG_PATH
cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64-unknown-openbsd
cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64_unknown_openbsd
cargo:rerun-if-env-changed=HOST_PKG_CONFIG_LIBDIR
cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-openbsd
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_openbsd
cargo:rerun-if-env-changed=HOST_PKG_CONFIG_SYSROOT_DIR
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
--- stderr
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21
stack backtrace:
0: __register_frame_info
1: __register_frame_info
2: __register_frame_info
3: __register_frame_info
4: __register_frame_info
5: __register_frame_info
6: __register_frame_info
7: __register_frame_info
8: __register_frame_info
9: __register_frame_info
10: __register_frame_info
11: __register_frame_info
12: __register_frame_info
13: __register_frame_info
14: __register_frame_info
15: <unknown>
Hey!
Your examples mostly showcase usage with raw bytes. Could you help me out on working with a String that I want to securely store inside one of the Secret variants? The String is read from the tty (it's a user-entered password).
The SecretBox
documentation showcases an example where some bytes are moved into SecretVec
by using the from
method. Is that currently the only way to accomplish this?
Thanks for helping me out!
In this example I want to encrypt a text that is stored on a file (I tried first to have it provided by stdin but I couldn't make it work).
use std::fs::File;
use std::io::Read;
use libsodium_sys as sodium;
use secrets::{SecretBox, SecretVec};
const KEY_LEN : usize = sodium::crypto_secretbox_KEYBYTES as _;
const NONCE_LEN : usize = sodium::crypto_secretbox_NONCEBYTES as _;
const MAC_LEN : usize = sodium::crypto_secretbox_MACBYTES as _;
pub fn get_ciphertext(key_path: &str, nonce_path: &str, text_path: &str) -> std::io::Result<SecretVec::<u8>>{
let mut key = SecretBox::<[u8; KEY_LEN]>::zero();
let mut nonce = [0; NONCE_LEN];
let mut plaintext = SecretVec::zero(14);
File::open(key_path)?
.read_exact(key.borrow_mut().as_mut())?;
File::open(nonce_path)?
.read_exact(&mut nonce)?;
File::open(text_path)?
.read_exact(plaintext.borrow_mut().as_mut())?;
Ok(SecretVec::<u8>::new(plaintext.len() - MAC_LEN, |s| {
if -1 == unsafe {
sodium::crypto_secretbox_easy(
s.as_mut_ptr(),
plaintext.borrow().as_ptr(),
plaintext.len() as _,
nonce.as_ptr(),
key.borrow().as_ptr(),
)
} {
panic!("failed");
}
}))
}
This is like the decrypt example but using the sodium::crypto_secretbox_easy
instead.
It gives the error thread 'main' panicked at 'attempt to subtract with overflow'
probably because of the size given by plaintext.len() - MAC_LEN
.
Have you any idea on how to fix this?
Hello!
It is more a question. Is there a good way to keep sensitive data in binary?
Forward thank you!
One way is what OpenSSH does, which is encrypting sensitive information with a random prekey of 16kb size. Because of the size, attacker is unlikely to retrieve prekey with the current attacks.
OpenSSH commit: openbsd/src@707316f
This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic
on IRC to discuss.
You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.
TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.
The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.
Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.
To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):
// Copyright 2016 secrets Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.
Be sure to add the relevant LICENSE-{MIT,APACHE}
files. You can copy these
from the Rust repo for a plain-text
version.
And don't forget to update the license
metadata in your Cargo.toml
to:
license = "MIT OR Apache-2.0"
I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!
To agree to relicensing, comment with :
I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.
Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.
There is crate called memsec which is a pure Rust implementation of libsodium/utils.
Maybe we can replace libsodium entirely? I'm willing to open a PR.
FWIW, libsodium
recently added an mshield
function that performs in-memory encryption. When that is stabilized and released, I'll be able to use it.
Of course, anyone with similar privileges can still find the key and IV in memory and decrypt the secret, but it does increase the level of effort for such an attach.
Originally posted by @stouset in #72 (comment)
That was the result of an other issue from last year, is that still on the roaster?
The documentation for secrets::traits::Bytes
states:
Any type that implements Bytes must not exhibit undefined behavior when its underlying bits are set to any arbitrary bit pattern.
Currently, bool
and char
(the primitive types) have implementations for Bytes
(https://github.com/stouset/secrets/blob/master/src/traits.rs#L69 ), but these types can not be set to arbitrary bit patterns (specifically, bool
must have the bit pattern 0x00
or 0x01
, and char
must have a bit pattern in the range 0x0000_0000..=0x0000_D7FF
or the range 0x0000_E000..=0x0010_FFFF
)
The following example program exhibits undefined behavior due to this (run it in debug mode and in release mode and you'll most likely see different results):
fn main() {
let b: char = secrets::traits::Bytes::uninitialized();
match b {
// Note that these two patterns together include all valid char values
'\x00'..='\u{10fffe}' => dbg!("char1"),
'\x01'..='\u{10ffff}' => dbg!("char2"), // This prints in release mode on my machine (secrets 1.2.0, rustc 1.61.0)
_ => dbg!("huh?"), // This prints in debug mode on my machine
};
}
https://github.com/stouset/secrets/blob/master/src/secret.rs#L215
For the Drop
implementation of Secret<T>
(linked above), why do you assert if the thread is panicking when the target is not on Windows and munlock
was successful?
My purpose is to understand and learn from you.
Thank you.
Hello,
i tried the code and it looks like it does not protect against reading the process memory with gcore from gdb.
code:
use std::fs::File;
use std::io::Read;
use std::io::Error;
use std::time::Duration;
use std::thread::sleep;
use secrets::SecretBox;
const KEY_LEN : usize = 10;
fn main() -> Result<(), Error> {
let mut key = SecretBox::<[u8; KEY_LEN]>::zero();
File::open("key.txt")?
.read_exact(key.borrow_mut().as_mut())?;
let mut cnt = 0u32;
loop {
cnt += 1;
sleep(Duration::from_secs(60));
if cnt == 10 {
break;
}
}
Ok(())
}
I f you use
# gcore -a -o rust_secret_process_dump $PID
you will find the content of key.txt with the strings tool in the generated
process memory dump.
# strings rust_secret_process_dump.$PID | grep (cat key.txt)
Maybe i missed that this class of attack is not what the library intends to protect from, but could someone elaborate on that.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.