Skip to content

Commit 597f1aa

Browse files
authored
Merge pull request str4d#544 from str4d/pre-release-changes
Pre-release changes
2 parents baf277a + ae5a392 commit 597f1aa

32 files changed

Lines changed: 1029 additions & 691 deletions

Cargo.lock

Lines changed: 124 additions & 115 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ cookie-factory = "0.3.1"
4848
nom = { version = "7", default-features = false, features = ["alloc"] }
4949

5050
# Secret management
51-
pinentry = "0.5"
52-
secrecy = "0.8"
51+
pinentry = "0.6"
52+
secrecy = "0.10"
5353
subtle = "2"
5454
zeroize = "1"
5555

age-core/CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ to 1.0.0 are beta releases.
88

99
## [Unreleased]
1010
### Added
11-
- `age_core::format::is_arbitrary_string`
11+
- `age_core::format`:
12+
- `FileKey::new`
13+
- `FileKey::init_with_mut`
14+
- `FileKey::try_init_with_mut`
15+
- `is_arbitrary_string`
1216

1317
### Changed
18+
- Migrated to `secrecy 0.10`.
1419
- `age::plugin::Connection::unidir_receive` now takes an additional argument to
1520
enable handling an optional fourth command.
1621

age-core/src/format.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rand::{
55
distributions::{Distribution, Uniform},
66
thread_rng, RngCore,
77
};
8-
use secrecy::{ExposeSecret, Secret};
8+
use secrecy::{ExposeSecret, ExposeSecretMut, SecretBox};
99

1010
/// The prefix identifying an age stanza.
1111
const STANZA_TAG: &str = "-> ";
@@ -14,11 +14,26 @@ const STANZA_TAG: &str = "-> ";
1414
pub const FILE_KEY_BYTES: usize = 16;
1515

1616
/// A file key for encrypting or decrypting an age file.
17-
pub struct FileKey(Secret<[u8; FILE_KEY_BYTES]>);
17+
pub struct FileKey(SecretBox<[u8; FILE_KEY_BYTES]>);
1818

19-
impl From<[u8; FILE_KEY_BYTES]> for FileKey {
20-
fn from(file_key: [u8; FILE_KEY_BYTES]) -> Self {
21-
FileKey(Secret::new(file_key))
19+
impl FileKey {
20+
/// Creates a file key using a pre-boxed key.
21+
pub fn new(file_key: Box<[u8; FILE_KEY_BYTES]>) -> Self {
22+
Self(SecretBox::new(file_key))
23+
}
24+
25+
/// Creates a file key using a function that can initialize the key in-place.
26+
pub fn init_with_mut(ctr: impl FnOnce(&mut [u8; FILE_KEY_BYTES])) -> Self {
27+
Self(SecretBox::init_with_mut(ctr))
28+
}
29+
30+
/// Same as [`Self::init_with_mut`], but the constructor can be fallible.
31+
pub fn try_init_with_mut<E>(
32+
ctr: impl FnOnce(&mut [u8; FILE_KEY_BYTES]) -> Result<(), E>,
33+
) -> Result<Self, E> {
34+
let mut file_key = SecretBox::new(Box::new([0; FILE_KEY_BYTES]));
35+
ctr(file_key.expose_secret_mut())?;
36+
Ok(Self(file_key))
2237
}
2338
}
2439

age-core/src/plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! implementations built around the `age-plugin` crate.
55
66
use rand::{thread_rng, Rng};
7-
use secrecy::Zeroize;
7+
use secrecy::zeroize::Zeroize;
88
use std::env;
99
use std::fmt;
1010
use std::io::{self, BufRead, BufReader, Read, Write};

age-plugin/examples/age-plugin-unencrypted.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,14 @@ impl IdentityPluginV1 for IdentityPlugin {
175175
// identities.
176176
let _ = callbacks.message("This identity does nothing!")?;
177177
file_keys.entry(file_index).or_insert_with(|| {
178-
Ok(FileKey::from(
179-
TryInto::<[u8; 16]>::try_into(&stanza.body[..]).unwrap(),
180-
))
178+
FileKey::try_init_with_mut(|file_key| {
179+
if stanza.body.len() == file_key.len() {
180+
file_key.copy_from_slice(&stanza.body);
181+
Ok(())
182+
} else {
183+
panic!("File key is wrong length")
184+
}
185+
})
181186
});
182187
break;
183188
}

age-plugin/src/identity.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl<'a, 'b, R: io::Read, W: io::Write> Callbacks<Error> for BidirCallbacks<'a,
135135
.and_then(|res| match res {
136136
Ok(s) => String::from_utf8(s.body)
137137
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "secret is not UTF-8"))
138-
.map(|s| Ok(SecretString::new(s))),
138+
.map(|s| Ok(SecretString::from(s))),
139139
Err(e) => Ok(Err(e)),
140140
})
141141
}

age-plugin/src/recipient.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Recipient plugin helpers.
22
33
use age_core::{
4-
format::{is_arbitrary_string, FileKey, Stanza, FILE_KEY_BYTES},
4+
format::{is_arbitrary_string, FileKey, Stanza},
55
plugin::{self, BidirSend, Connection},
66
secrecy::SecretString,
77
};
@@ -81,8 +81,12 @@ pub trait RecipientPluginV1 {
8181
/// Wraps each `file_key` to all recipients and identities previously added via
8282
/// `add_recipient` and `add_identity`.
8383
///
84-
/// Returns either one stanza per recipient and identity for each file key, or any
85-
/// errors if one or more recipients or identities could not be wrapped to.
84+
/// Returns a set of stanzas per file key that wrap it to each recipient and identity.
85+
/// Plugins may return more than one stanza per "actual recipient", e.g. to support
86+
/// multiple formats, to build group aliases, or to act as a proxy.
87+
///
88+
/// If one or more recipients or identities could not be wrapped to, no stanzas are
89+
/// returned for any of the file keys.
8690
///
8791
/// `callbacks` can be used to interact with the user, to have them take some physical
8892
/// action or request a secret value.
@@ -183,7 +187,7 @@ impl<'a, 'b, R: io::Read, W: io::Write> Callbacks<Error> for BidirCallbacks<'a,
183187
.and_then(|res| match res {
184188
Ok(s) => String::from_utf8(s.body)
185189
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "secret is not UTF-8"))
186-
.map(|s| Ok(SecretString::new(s))),
190+
.map(|s| Ok(SecretString::from(s))),
187191
Err(e) => Ok(Err(e)),
188192
})
189193
}
@@ -281,11 +285,16 @@ pub(crate) fn run_v1<P: RecipientPluginV1>(mut plugin: P) -> io::Result<()> {
281285
}),
282286
(Some(WRAP_FILE_KEY), |s| {
283287
// TODO: Should we ignore file key commands with unexpected metadata args?
284-
TryInto::<[u8; FILE_KEY_BYTES]>::try_into(&s.body[..])
285-
.map_err(|_| Error::Internal {
286-
message: "invalid file key length".to_owned(),
287-
})
288-
.map(FileKey::from)
288+
FileKey::try_init_with_mut(|file_key| {
289+
if s.body.len() == file_key.len() {
290+
file_key.copy_from_slice(&s.body);
291+
Ok(())
292+
} else {
293+
Err(Error::Internal {
294+
message: "invalid file key length".to_owned(),
295+
})
296+
}
297+
})
289298
}),
290299
(Some(EXTENSION_LABELS), |_| Ok(())),
291300
)?;

age/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ to 1.0.0 are beta releases.
2626
- Partial French translation!
2727

2828
### Changed
29-
- Migrated to `i18n-embed 0.15`.
29+
- Migrated to `i18n-embed 0.15`, `secrecy 0.10`.
3030
- `age::Encryptor::with_recipients` now takes recipients by reference instead of
3131
by value. This aligns it with `age::Decryptor` (which takes identities by
3232
reference), and also means that errors with recipients are reported earlier.

age/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ futures = { version = "0.3", optional = true }
3737
pin-project = "1"
3838

3939
# Common CLI dependencies
40-
pinentry = { version = "0.5", optional = true }
40+
pinentry = { workspace = true, optional = true }
4141

4242
# Dependencies used internally:
4343
# (Breaking upgrades to these are usually backwards-compatible, but check MSRVs.)

0 commit comments

Comments
 (0)