+1
-1
@@ -8,7 +8,7 @@ to 0.3.0 are beta releases.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Changed
|
### Changed
|
||||||
- MSRV is now 1.60.0.
|
- MSRV is now 1.65.0.
|
||||||
- The YubiKey PIV PIN and touch caches are now preserved across processes in
|
- The YubiKey PIV PIN and touch caches are now preserved across processes in
|
||||||
most cases. See [README.md](README.md#agent-support) for exceptions. This has
|
most cases. See [README.md](README.md#agent-support) for exceptions. This has
|
||||||
several usability effects (not applicable to YubiKey 4 series):
|
several usability effects (not applicable to YubiKey 4 series):
|
||||||
|
|||||||
Generated
+369
-348
File diff suppressed because it is too large
Load Diff
+5
-8
@@ -9,7 +9,7 @@ keywords = ["age", "cli", "encryption", "yubikey"]
|
|||||||
categories = ["command-line-utilities", "cryptography"]
|
categories = ["command-line-utilities", "cryptography"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.60" # MSRV
|
rust-version = "1.65" # MSRV
|
||||||
|
|
||||||
[package.metadata.deb]
|
[package.metadata.deb]
|
||||||
extended-description = """\
|
extended-description = """\
|
||||||
@@ -24,7 +24,7 @@ assets = [
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
age-core = "0.9"
|
age-core = "0.9"
|
||||||
age-plugin = "0.4"
|
age-plugin = "0.4"
|
||||||
base64 = "0.20"
|
base64 = "0.21"
|
||||||
bech32 = "0.9"
|
bech32 = "0.9"
|
||||||
console = { version = "0.15", default-features = false }
|
console = { version = "0.15", default-features = false }
|
||||||
dialoguer = { version = "0.10", default-features = false, features = ["password"] }
|
dialoguer = { version = "0.10", default-features = false, features = ["password"] }
|
||||||
@@ -32,14 +32,14 @@ env_logger = "0.10"
|
|||||||
gumdrop = "0.8"
|
gumdrop = "0.8"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
p256 = { version = "0.11", features = ["ecdh"] }
|
p256 = { version = "0.13", features = ["ecdh"] }
|
||||||
pcsc = "2.4"
|
pcsc = "2.4"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
which = "4.1"
|
which = "4.1"
|
||||||
x509 = "0.2"
|
x509 = "0.2"
|
||||||
x509-parser = "0.14"
|
x509-parser = "0.14"
|
||||||
yubikey = { version = "0.7", features = ["untested"] }
|
yubikey = { version = "=0.8.0-pre.0", features = ["untested"] }
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
i18n-embed = { version = "0.13", features = ["desktop-requester", "fluent-system"] }
|
i18n-embed = { version = "0.13", features = ["desktop-requester", "fluent-system"] }
|
||||||
@@ -48,7 +48,7 @@ lazy_static = "1"
|
|||||||
rust-embed = "6"
|
rust-embed = "6"
|
||||||
|
|
||||||
# GnuPG coexistence
|
# GnuPG coexistence
|
||||||
sysinfo = "0.27"
|
sysinfo = "0.28"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
@@ -56,6 +56,3 @@ man = "0.3"
|
|||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
test-with = "0.9"
|
test-with = "0.9"
|
||||||
which = "4"
|
which = "4"
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
yubikey = { git = "https://github.com/iqlusioninc/yubikey.rs.git", rev = "1d33ea174791f699dfc0e6a06648aa3d9e066144" }
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ which enables files to be encrypted to age identities stored on YubiKeys.
|
|||||||
On Windows, Linux, and macOS, you can use the
|
On Windows, Linux, and macOS, you can use the
|
||||||
[pre-built binaries](https://github.com/str4d/age-plugin-yubikey/releases).
|
[pre-built binaries](https://github.com/str4d/age-plugin-yubikey/releases).
|
||||||
|
|
||||||
If your system has Rust 1.60+ installed (either via `rustup` or a system
|
If your system has Rust 1.65+ installed (either via `rustup` or a system
|
||||||
package), you can build directly from source:
|
package), you can build directly from source:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.60.0"
|
channel = "1.65.0"
|
||||||
components = ["clippy", "rustfmt"]
|
components = ["clippy", "rustfmt"]
|
||||||
|
|||||||
+8
-14
@@ -3,6 +3,7 @@ use age_core::{
|
|||||||
primitives::aead_encrypt,
|
primitives::aead_encrypt,
|
||||||
secrecy::ExposeSecret,
|
secrecy::ExposeSecret,
|
||||||
};
|
};
|
||||||
|
use base64::{prelude::BASE64_STANDARD_NO_PAD, Engine};
|
||||||
use p256::{
|
use p256::{
|
||||||
ecdh::EphemeralSecret,
|
ecdh::EphemeralSecret,
|
||||||
elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint},
|
elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint},
|
||||||
@@ -18,14 +19,6 @@ const TAG_BYTES: usize = 4;
|
|||||||
const EPK_BYTES: usize = 33;
|
const EPK_BYTES: usize = 33;
|
||||||
const ENCRYPTED_FILE_KEY_BYTES: usize = 32;
|
const ENCRYPTED_FILE_KEY_BYTES: usize = 32;
|
||||||
|
|
||||||
const STANDARD_NO_PAD: &base64::engine::fast_portable::FastPortable = {
|
|
||||||
use base64::{
|
|
||||||
alphabet::STANDARD,
|
|
||||||
engine::fast_portable::{FastPortable, NO_PAD},
|
|
||||||
};
|
|
||||||
&FastPortable::from(&STANDARD, NO_PAD)
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The ephemeral key bytes in a piv-p256 stanza.
|
/// The ephemeral key bytes in a piv-p256 stanza.
|
||||||
///
|
///
|
||||||
/// The bytes contain a compressed SEC-1 encoding of a valid point.
|
/// The bytes contain a compressed SEC-1 encoding of a valid point.
|
||||||
@@ -34,7 +27,7 @@ pub(crate) struct EphemeralKeyBytes(p256::EncodedPoint);
|
|||||||
|
|
||||||
impl EphemeralKeyBytes {
|
impl EphemeralKeyBytes {
|
||||||
fn from_bytes(bytes: [u8; EPK_BYTES]) -> Option<Self> {
|
fn from_bytes(bytes: [u8; EPK_BYTES]) -> Option<Self> {
|
||||||
let encoded = p256::EncodedPoint::from_bytes(&bytes).ok()?;
|
let encoded = p256::EncodedPoint::from_bytes(bytes).ok()?;
|
||||||
if encoded.is_compressed()
|
if encoded.is_compressed()
|
||||||
&& p256::PublicKey::from_encoded_point(&encoded)
|
&& p256::PublicKey::from_encoded_point(&encoded)
|
||||||
.is_some()
|
.is_some()
|
||||||
@@ -73,8 +66,8 @@ impl From<RecipientLine> for Stanza {
|
|||||||
Stanza {
|
Stanza {
|
||||||
tag: STANZA_TAG.to_owned(),
|
tag: STANZA_TAG.to_owned(),
|
||||||
args: vec![
|
args: vec![
|
||||||
base64::encode_engine(&r.tag, STANDARD_NO_PAD),
|
BASE64_STANDARD_NO_PAD.encode(r.tag),
|
||||||
base64::encode_engine(r.epk_bytes.as_bytes(), STANDARD_NO_PAD),
|
BASE64_STANDARD_NO_PAD.encode(r.epk_bytes.as_bytes()),
|
||||||
],
|
],
|
||||||
body: r.encrypted_file_key.to_vec(),
|
body: r.encrypted_file_key.to_vec(),
|
||||||
}
|
}
|
||||||
@@ -92,9 +85,10 @@ impl RecipientLine {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
base64::decode_engine_slice(arg, buf.as_mut(), STANDARD_NO_PAD)
|
BASE64_STANDARD_NO_PAD
|
||||||
|
.decode_slice_unchecked(arg, buf.as_mut())
|
||||||
.ok()
|
.ok()
|
||||||
.map(|_| buf)
|
.and_then(|len| (len == buf.as_mut().len()).then_some(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
let (tag, epk_bytes) = match &s.args[..] {
|
let (tag, epk_bytes) = match &s.args[..] {
|
||||||
@@ -117,7 +111,7 @@ impl RecipientLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn wrap_file_key(file_key: &FileKey, pk: &Recipient) -> Self {
|
pub(crate) fn wrap_file_key(file_key: &FileKey, pk: &Recipient) -> Self {
|
||||||
let esk = EphemeralSecret::random(OsRng);
|
let esk = EphemeralSecret::random(&mut OsRng);
|
||||||
let epk = esk.public_key();
|
let epk = esk.public_key();
|
||||||
let epk_bytes = EphemeralKeyBytes::from_public_key(&epk);
|
let epk_bytes = EphemeralKeyBytes::from_public_key(&epk);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user