-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ssh-key: create
Keypair
and KeyData
variants for custom algorithms.
Adds the `Keypair::Other` and `KeyData::Other` variants for storing the key material of keys that use a custom algorithm. Adds the `OpaqueKeypair` and `OpaqueKeyData` types for representing keys meant to be used with an algorithm unknown to this crate (e.g. custom algorithms). They are said to be opaque, because the meaning of their underlying byte representation is not specified.
- Loading branch information
Showing
10 changed files
with
398 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
//! Opaque private keys. | ||
//! | ||
//! [`OpaqueKeypair`] represents a keypair meant to be used with an algorithm unknown to this | ||
//! crate, i.e. keypairs that use a custom algorithm as specified in [RFC4251 § 6]. | ||
//! | ||
//! They are said to be opaque, because the meaning of their underlying byte representation is not | ||
//! specified. | ||
//! | ||
//! [RFC4251 § 6]: https://www.rfc-editor.org/rfc/rfc4251.html#section-6 | ||
|
||
use crate::{ | ||
public::{OpaquePublicKey, OpaquePublicKeyBytes}, | ||
Algorithm, Error, Result, | ||
}; | ||
use alloc::vec::Vec; | ||
use core::fmt; | ||
use encoding::{CheckedSum, Decode, Encode, Reader, Writer}; | ||
use subtle::{Choice, ConstantTimeEq}; | ||
|
||
/// An opaque private key. | ||
/// | ||
/// The encoded representation of an `OpaquePrivateKeyBytes` consists of a 4-byte length prefix, | ||
/// followed by its byte representation. | ||
#[derive(Clone)] | ||
pub struct OpaquePrivateKeyBytes(Vec<u8>); | ||
|
||
/// An opaque keypair. | ||
/// | ||
/// The encoded representation of an `OpaqueKeypair` consists of the encoded representation of its | ||
/// [`OpaquePublicKey`] followed by the encoded representation of its [`OpaquePrivateKeyBytes`]. | ||
#[derive(Clone)] | ||
pub struct OpaqueKeypair { | ||
/// The opaque private key | ||
pub private: OpaquePrivateKeyBytes, | ||
/// The opaque public key | ||
pub public: OpaquePublicKey, | ||
} | ||
|
||
/// The underlying representation of an [`OpaqueKeypair`]. | ||
/// | ||
/// The encoded representation of an `OpaqueKeypairBytes` consists of the encoded representation of | ||
/// its [`OpaquePublicKeyBytes`] followed by the encoded representation of its | ||
/// [`OpaquePrivateKeyBytes`]. | ||
pub struct OpaqueKeypairBytes { | ||
/// The opaque private key | ||
pub private: OpaquePrivateKeyBytes, | ||
/// The opaque public key | ||
pub public: OpaquePublicKeyBytes, | ||
} | ||
|
||
impl OpaqueKeypair { | ||
/// Create a new `OpaqueKeypair`. | ||
pub fn new(private_key: Vec<u8>, public: OpaquePublicKey) -> Self { | ||
Self { | ||
private: OpaquePrivateKeyBytes(private_key), | ||
public, | ||
} | ||
} | ||
|
||
/// Get the [`Algorithm`] for this key type. | ||
pub fn algorithm(&self) -> Algorithm { | ||
self.public.algorithm() | ||
} | ||
|
||
/// Decode [`OpaqueKeypair`] for the specified algorithm. | ||
pub(super) fn decode_as(reader: &mut impl Reader, algorithm: Algorithm) -> Result<Self> { | ||
let key = OpaqueKeypairBytes::decode(reader)?; | ||
let public = OpaquePublicKey { | ||
algorithm, | ||
key: key.public, | ||
}; | ||
|
||
Ok(Self { | ||
public, | ||
private: key.private, | ||
}) | ||
} | ||
} | ||
|
||
impl Decode for OpaquePrivateKeyBytes { | ||
type Error = Error; | ||
|
||
fn decode(reader: &mut impl Reader) -> Result<Self> { | ||
let len = usize::decode(reader)?; | ||
let mut bytes = vec![0; len]; | ||
reader.read(&mut bytes)?; | ||
Ok(Self(bytes)) | ||
} | ||
} | ||
|
||
impl Decode for OpaqueKeypairBytes { | ||
type Error = Error; | ||
|
||
fn decode(reader: &mut impl Reader) -> Result<Self> { | ||
let public = OpaquePublicKeyBytes::decode(reader)?; | ||
let private = OpaquePrivateKeyBytes::decode(reader)?; | ||
|
||
Ok(Self { public, private }) | ||
} | ||
} | ||
|
||
impl Encode for OpaqueKeypair { | ||
fn encoded_len(&self) -> encoding::Result<usize> { | ||
[self.public.encoded_len()?, self.private.encoded_len()?].checked_sum() | ||
} | ||
|
||
fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> { | ||
self.public.encode(writer)?; | ||
self.private.encode(writer)?; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl ConstantTimeEq for OpaqueKeypair { | ||
fn ct_eq(&self, other: &Self) -> Choice { | ||
Choice::from((self.public == other.public) as u8) & self.private.ct_eq(&other.private) | ||
} | ||
} | ||
|
||
impl Encode for OpaquePrivateKeyBytes { | ||
fn encoded_len(&self) -> encoding::Result<usize> { | ||
self.0.encoded_len() | ||
} | ||
|
||
fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> { | ||
self.0.encode(writer) | ||
} | ||
} | ||
|
||
impl From<&OpaqueKeypair> for OpaquePublicKey { | ||
fn from(keypair: &OpaqueKeypair) -> OpaquePublicKey { | ||
keypair.public.clone() | ||
} | ||
} | ||
|
||
impl fmt::Debug for OpaqueKeypair { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("OpaqueKeypair") | ||
.field("public", &self.public) | ||
.finish_non_exhaustive() | ||
} | ||
} | ||
|
||
impl ConstantTimeEq for OpaquePrivateKeyBytes { | ||
fn ct_eq(&self, other: &Self) -> Choice { | ||
self.as_ref().ct_eq(other.as_ref()) | ||
} | ||
} | ||
|
||
impl AsRef<[u8]> for OpaquePrivateKeyBytes { | ||
fn as_ref(&self) -> &[u8] { | ||
&self.0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.