summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNora Widdecke <nora@sequoia-pgp.org>2020-04-06 16:42:57 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-11-30 15:56:37 +0100
commit98316651354ff2ead858833e1c0e855f67fb8234 (patch)
treebe80d654a206cdde42b837f315fff6059d504f4d
parent714695daad6dfcfbc94c5071328c9846e4294641 (diff)
openpgp: Improve documentation of Fingerprint, KeyID, and KeyHandle.
- Fixes #465.
-rw-r--r--openpgp/src/fingerprint.rs169
-rw-r--r--openpgp/src/keyhandle.rs68
-rw-r--r--openpgp/src/keyid.rs165
3 files changed, 334 insertions, 68 deletions
diff --git a/openpgp/src/fingerprint.rs b/openpgp/src/fingerprint.rs
index 42a5c313..3af4a70e 100644
--- a/openpgp/src/fingerprint.rs
+++ b/openpgp/src/fingerprint.rs
@@ -5,21 +5,52 @@ use quickcheck::{Arbitrary, Gen};
/// A long identifier for certificates and keys.
///
-/// A fingerprint uniquely identifies a public key. For more details
-/// about how a fingerprint is generated, see [Section 12.2 of RFC
-/// 4880].
+/// A `Fingerprint` uniquely identifies a public key.
///
+/// Currently, sequoia supports *version 4* fingerprints and Key IDs
+/// only. *Version 3* fingerprints and Key IDs were deprecated by
+/// [RFC 4880] in 2007.
+///
+/// Essentially, a *v4* fingerprint is a SHA-1 hash over the key's
+/// public key packet. For details, see [Section 12.2 of RFC 4880].
+///
+/// Fingerprints are used, for example, to reference the issuing key
+/// of a signature in its [`IssuerFingerprint`] subpacket. As a
+/// general rule of thumb, you should prefer using fingerprints over
+/// KeyIDs because the latter are vulnerable to [birthday attack]s.
+///
+/// See also [`KeyID`] and [`KeyHandle`].
+///
+/// [RFC 4880]: https://tools.ietf.org/html/rfc4880
/// [Section 12.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-12.2
+/// [`KeyID`]: ./enum.KeyID.html
+/// [`KeyHandle`]: ./enum.KeyHandle.html
+/// [`IssuerFingerprint`]: ./packet/signature/subpacket/enum.SubpacketValue.html#variant.IssuerFingerprint
+/// [birthday attack]: https://nullprogram.com/blog/2019/07/22/
///
/// Note: This enum cannot be exhaustively matched to allow future
/// extensions.
+///
+/// # Examples
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// # use sequoia_openpgp as openpgp;
+/// use openpgp::Fingerprint;
+///
+/// let fp: Fingerprint =
+/// "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567".parse()?;
+///
+/// assert_eq!("0123456789ABCDEF0123456789ABCDEF01234567", fp.to_hex());
+/// # Ok(()) }
+/// ```
#[non_exhaustive]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum Fingerprint {
- /// 20 byte SHA-1 hash.
+ /// A 20 byte SHA-1 hash of the public key packet as defined in the RFC.
V4([u8;20]),
- /// Used for holding fingerprints that we don't understand. For
- /// instance, we don't grok v3 fingerprints.
+ /// Used for holding fingerprint data that is not a V4 fingerprint, e.g. a
+ /// V3 fingerprint (deprecated) or otherwise wrong-length data.
Invalid(Box<[u8]>),
}
@@ -60,7 +91,25 @@ impl std::str::FromStr for Fingerprint {
}
impl Fingerprint {
- /// Reads a binary fingerprint.
+ /// Creates a `Fingerprint` from a byte slice in big endian
+ /// representation.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
+ /// # use sequoia_openpgp as openpgp;
+ /// use openpgp::Fingerprint;
+ ///
+ /// let fp: Fingerprint =
+ /// "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567".parse()?;
+ /// let bytes =
+ /// [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23,
+ /// 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67];
+ ///
+ /// assert_eq!(Fingerprint::from_bytes(&bytes), fp);
+ /// # Ok(()) }
+ /// ```
pub fn from_bytes(raw: &[u8]) -> Fingerprint {
if raw.len() == 20 {
let mut fp : [u8; 20] = Default::default();
@@ -71,7 +120,24 @@ impl Fingerprint {
}
}
- /// Returns a reference to the raw Fingerprint.
+ /// Returns the raw fingerprint as a byte slice in big endian
+ /// representation.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
+ /// # use sequoia_openpgp as openpgp;
+ /// use openpgp::Fingerprint;
+ ///
+ /// let fp: Fingerprint =
+ /// "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567".parse()?;
+ ///
+ /// assert_eq!(fp.as_bytes(),
+ /// [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23,
+ /// 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67]);
+ /// # Ok(()) }
+ /// ```
pub fn as_bytes(&self) -> &[u8] {
match self {
&Fingerprint::V4(ref fp) => fp,
@@ -79,44 +145,53 @@ impl Fingerprint {
}
}
- /// Converts this fingerprint to its canonical hexadecimal representation.
+ /// Converts this fingerprint to its canonical hexadecimal
+ /// representation.
///
- /// This representation is always uppercase and without spaces and is
- /// suitable for stable key identifiers.
+ /// This representation is always uppercase and without spaces and
+ /// is suitable for stable key identifiers.
///
- /// The output of this function is exactly the same as formatting this
- /// object with the `:X` format specifier.
+ /// The output of this function is exactly the same as formatting
+ /// this object with the `:X` format specifier.
///
/// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
/// # use sequoia_openpgp as openpgp;
/// use openpgp::Fingerprint;
///
- /// let fpr = "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567".parse::<Fingerprint>().unwrap();
+ /// let fp: Fingerprint =
+ /// "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567".parse()?;
///
- /// assert_eq!("0123456789ABCDEF0123456789ABCDEF01234567", fpr.to_hex());
- /// assert_eq!(format!("{:X}", fpr), fpr.to_hex());
+ /// assert_eq!("0123456789ABCDEF0123456789ABCDEF01234567", fp.to_hex());
+ /// assert_eq!(format!("{:X}", fp), fp.to_hex());
+ /// # Ok(()) }
/// ```
pub fn to_hex(&self) -> String {
format!("{:X}", self)
}
- /// Parses the hexadecimal representation of an OpenPGP fingerprint.
+ /// Parses the hexadecimal representation of an OpenPGP
+ /// fingerprint.
///
- /// This function is the reverse of `to_hex`. It also accepts other variants
- /// of the fingerprint notation including lower-case letters, spaces and
- /// optional leading `0x`.
+ /// This function is the reverse of `to_hex`. It also accepts
+ /// other variants of the fingerprint notation including
+ /// lower-case letters, spaces and optional leading `0x`.
///
/// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
/// # use sequoia_openpgp as openpgp;
/// use openpgp::Fingerprint;
///
- /// let fpr = Fingerprint::from_hex("0123456789ABCDEF0123456789ABCDEF01234567").unwrap();
+ /// let fp =
+ /// Fingerprint::from_hex("0123456789ABCDEF0123456789ABCDEF01234567")?;
///
- /// assert_eq!("0123456789ABCDEF0123456789ABCDEF01234567", fpr.to_hex());
+ /// assert_eq!("0123456789ABCDEF0123456789ABCDEF01234567", fp.to_hex());
///
- /// let fpr = Fingerprint::from_hex("0123 4567 89ab cdef 0123 4567 89ab cdef 0123 4567").unwrap();
+ /// let fp =
+ /// Fingerprint::from_hex("0123 4567 89ab cdef 0123 4567 89ab cdef 0123 4567")?;
///
- /// assert_eq!("0123456789ABCDEF0123456789ABCDEF01234567", fpr.to_hex());
+ /// assert_eq!("0123456789ABCDEF0123456789ABCDEF01234567", fp.to_hex());
+ /// # Ok(()) }
/// ```
pub fn from_hex(s: &str) -> std::result::Result<Self, anyhow::Error> {
std::str::FromStr::from_str(s)
@@ -175,8 +250,32 @@ impl Fingerprint {
String::from_utf8(output).unwrap()
}
- /// Converts the hex representation of the fingerprint to a phrase in the
- /// ICAO alphabet.
+ /// Converts the hex representation of the `Fingerprint` to a
+ /// phrase in the [ICAO spelling alphabet].
+ ///
+ /// [ICAO spelling alphabet]: https://en.wikipedia.org/wiki/ICAO_spelling_alphabet
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
+ /// # use sequoia_openpgp as openpgp;
+ /// use openpgp::Fingerprint;
+ ///
+ /// let fp: Fingerprint =
+ /// "01AB 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567".parse()?;
+ ///
+ /// assert!(fp.to_icao().starts_with("Zero One Alfa Bravo"));
+ ///
+ /// # let expected = "\
+ /// # Zero One Alfa Bravo Four Five Six Seven Eight Niner Alfa Bravo \
+ /// # Charlie Delta Echo Foxtrot Zero One Two Three Four Five Six Seven \
+ /// # Eight Niner Alfa Bravo Charlie Delta Echo Foxtrot Zero One Two \
+ /// # Three Four Five Six Seven";
+ /// # assert_eq!(fp.to_icao(), expected);
+ /// #
+ /// # Ok(()) }
+ /// ```
pub fn to_icao(&self) -> String {
let mut ret = String::default();
@@ -226,23 +325,11 @@ mod tests {
use super::*;
#[test]
- fn icao() {
- let fpr = "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567"
- .parse::<Fingerprint>().unwrap();
- let expected = "\
-Zero One Two Three Four Five Six Seven Eight Niner Alfa Bravo Charlie Delta \
-Echo Foxtrot Zero One Two Three Four Five Six Seven Eight Niner Alfa Bravo \
-Charlie Delta Echo Foxtrot Zero One Two Three Four Five Six Seven";
-
- assert_eq!(fpr.to_icao(), expected);
- }
-
- #[test]
fn hex_formatting() {
- let fpr = "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567"
+ let fp = "0123 4567 89AB CDEF 0123 4567 89AB CDEF 0123 4567"
.parse::<Fingerprint>().unwrap();
- assert_eq!(format!("{:X}", fpr), "0123456789ABCDEF0123456789ABCDEF01234567");
- assert_eq!(format!("{:x}", fpr), "0123456789abcdef0123456789abcdef01234567");
+ assert_eq!(format!("{:X}", fp), "0123456789ABCDEF0123456789ABCDEF01234567");
+ assert_eq!(format!("{:x}", fp), "0123456789abcdef0123456789abcdef01234567");
}
#[test]
diff --git a/openpgp/src/keyhandle.rs b/openpgp/src/keyhandle.rs
index d3cd18a1..cfa78f3a 100644
--- a/openpgp/src/keyhandle.rs
+++ b/openpgp/src/keyhandle.rs
@@ -10,9 +10,68 @@ use crate::{
Result,
};
-/// Identifies certificates and keys.
+/// Enum representing an identifier for certificates and keys.
///
-/// A `KeyHandle` is either a `Fingerprint` or a `KeyID`.
+/// A `KeyHandle` contains either a [`Fingerprint`] or a [`KeyID`].
+/// This is needed because signatures can reference their issuer
+/// either by `Fingerprint` or by `KeyID`.
+///
+/// Currently, sequoia supports *version 4* fingerprints and Key ID
+/// only. *Version 3* fingerprints and Key ID were deprecated by [RFC
+/// 4880] in 2007.
+///
+/// A *v4* fingerprint is, essentially, a 20-byte SHA-1 hash over the
+/// key's public key packet. A *v4* Key ID is defined as the
+/// fingerprint's lower 8 bytes.
+///
+/// For the exact definition, see [Section 12.2 of RFC 4880].
+///
+/// Both fingerprint and Key ID are used to identify a key, e.g., the
+/// issuer of a signature.
+///
+/// [RFC 4880]: https://tools.ietf.org/html/rfc4880
+/// [Section 12.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-12.2
+/// [`Fingerprint`]: ./enum.Fingerprint.html
+/// [`KeyID`]: ./enum.KeyID.html
+///
+/// # Examples
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// # use sequoia_openpgp as openpgp;
+/// use openpgp::KeyHandle;
+/// use openpgp::Packet;
+/// use openpgp::parse::Parse;
+///
+/// let p = Packet::from_bytes(
+/// "-----BEGIN PGP SIGNATURE-----
+/// #
+/// # wsBzBAABCgAdFiEEwD+mQRsDrhJXZGEYciO1ZnjgJSgFAlnclx8ACgkQciO1Znjg
+/// # JShldAf+NBvUTVPnVPhYM4KihWOUlup8lbD6g1IduSM5rpsGvOVb+uKF6ik+GOBB
+/// # RlMT4s183r3teFxiTkDx2pRhUz0MnOMPfbXovjF6Y93fKCOxCQWLBa0ukjNmE+ax
+/// # gu9nZ3XXDGXZW22iGE52uVjPGSfuLfqvdMy5bKHn8xow/kepuGHZwy8yn7uFv7sl
+/// # LnOBUz1FKA7iRl457XKPUhw5K7BnfRW/I2BRlnrwTDkjfXaJZC+bUTIJvm682Bvt
+/// # ZNn8zc0JucyEkuL9WXYNuZg0znDE3T7D/6+tzfEdSf706unsXFXWHf83vL2eHCcw
+/// # qhImm1lmcC+agFtWQ6/qD923LR9xmg==
+/// # =htNu
+/// # -----END PGP SIGNATURE-----" /* docstring trickery ahead:
+/// // ...
+/// -----END PGP SIGNATURE-----")?;
+/// # */)?;
+/// if let Packet::Signature(sig) = p {
+/// let issuers = sig.get_issuers();
+/// assert_eq!(issuers.len(), 2);
+/// assert_eq!(&issuers[0],
+/// &KeyHandle::Fingerprint(
+/// "C03F A641 1B03 AE12 5764 6118 7223 B566 78E0 2528"
+/// .parse()?));
+/// assert_eq!(&issuers[1],
+/// &KeyHandle::KeyID("7223 B566 78E0 2528".parse()?));
+/// } else {
+/// unreachable!("It's a signature!");
+/// }
+/// # Ok(()) }
+/// ```
#[derive(Debug, Clone)]
pub enum KeyHandle {
/// A Fingerprint.
@@ -146,7 +205,7 @@ impl PartialEq for KeyHandle {
}
impl KeyHandle {
- /// Returns a reference to the raw identifier.
+ /// Returns the raw identifier as a byte slice.
pub fn as_bytes(&self) -> &[u8] {
match self {
KeyHandle::Fingerprint(i) => i.as_bytes(),
@@ -154,7 +213,8 @@ impl KeyHandle {
}
}
- /// Returns whether `self` and `other` could be aliases of each other.
+ /// Returns whether `self` and `other` could be aliases of each
+ /// other.
///
/// `KeyHandle`'s `PartialEq` implementation cannot assert that a
/// `Fingerprint` and a `KeyID` are equal, because distinct
diff --git a/openpgp/src/keyid.rs b/openpgp/src/keyid.rs
index a507527f..973b059e 100644
--- a/openpgp/src/keyid.rs
+++ b/openpgp/src/keyid.rs
@@ -9,22 +9,60 @@ use crate::Result;
/// A short identifier for certificates and keys.
///
-/// A KeyID is a fingerprint fragment. It identifies a public key,
-/// but is easy to forge. For more details about how a KeyID is
-/// generated, see [Section 12.2 of RFC 4880].
+/// A `KeyID` identifies a public key. It is used, for example, to
+/// reference the issuing key of a signature in its [`Issuer`]
+/// subpacket.
///
+/// Currently, sequoia supports *version 4* fingerprints and Key IDs
+/// only. *Version 3* fingerprints and Key IDs were deprecated by
+/// [RFC 4880] in 2007.
+///
+/// A *v4* `KeyID` is defined as a fragment (the lower 8 bytes) of the
+/// key's fingerprint, which in turn is essentially a SHA-1 hash of
+/// the public key packet. As a general rule of thumb, you should
+/// prefer the fingerprint as it is possible to create keys with a
+/// colliding KeyID using a [birthday attack].
+///
+/// For more details about how a `KeyID` is generated, see [Section
+/// 12.2 of RFC 4880].
+///
+/// In previous versions of OpenPGP, the Key ID used to be called
+/// "long Key ID", as there even was a "short Key ID". At only 4 bytes
+/// length, short Key IDs vulnerable to preimage attacks. That is, an
+/// attacker can create a key with any given short key ID in short
+/// amount of time.
+///
+/// See also [`Fingerprint`] and [`KeyHandle`].
+///
+/// [RFC 4880]: https://tools.ietf.org/html/rfc4880
/// [Section 12.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-12.2
+/// [`Fingerprint`]: ./enum.Fingerprint.html
+/// [`KeyHandle`]: ./enum.KeyHandle.html
+/// [birthday attack]: https://nullprogram.com/blog/2019/07/22/
+/// [`Issuer`]: ./packet/signature/subpacket/enum.SubpacketValue.html#variant.Issuer
///
/// Note: This enum cannot be exhaustively matched to allow future
/// extensions.
+///
+/// # Examples
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// # use sequoia_openpgp as openpgp;
+/// use openpgp::KeyID;
+///
+/// let id: KeyID = "0123 4567 89AB CDEF".parse()?;
+///
+/// assert_eq!("0123456789ABCDEF", id.to_hex());
+/// # Ok(()) }
+/// ```
#[non_exhaustive]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum KeyID {
/// Lower 8 byte SHA-1 hash.
V4([u8;8]),
- /// Used for holding keyids that we don't understand. For
- /// instance, we don't grok v3 keyids. And, it is possible that
- /// the Issuer subpacket contains the wrong number of bytes.
+ /// Used for holding invalid keyids encountered during parsing
+ /// e.g. wrong number of bytes.
Invalid(Box<[u8]>),
}
@@ -121,13 +159,35 @@ impl From<Fingerprint> for KeyID {
}
impl KeyID {
- /// Converts a u64 to a KeyID.
+ /// Converts a `u64` to a `KeyID`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::KeyID;
+ ///
+ /// let keyid = KeyID::new(0x0123456789ABCDEF);
+ /// ```
pub fn new(data: u64) -> KeyID {
let bytes = data.to_be_bytes();
Self::from_bytes(&bytes[..])
}
- /// Converts the KeyID to a u64 if possible.
+ /// Converts the `KeyID` to a `u64` if possible.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::KeyID;
+ ///
+ /// let keyid = KeyID::new(0x0123456789ABCDEF);
+ ///
+ /// assert_eq!(keyid.as_u64()?, 0x0123456789ABCDEF);
+ /// # Ok(()) }
+ /// ```
pub fn as_u64(&self) -> Result<u64> {
match &self {
KeyID::V4(ref b) =>
@@ -137,7 +197,21 @@ impl KeyID {
}
}
- /// Reads a binary key ID.
+ /// Creates a `KeyID` from a big endian byte slice.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::KeyID;
+ ///
+ /// let keyid: KeyID = "0123 4567 89AB CDEF".parse()?;
+ ///
+ /// let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
+ /// assert_eq!(KeyID::from_bytes(&bytes), keyid);
+ /// # Ok(()) }
+ /// ```
pub fn from_bytes(raw: &[u8]) -> KeyID {
if raw.len() == 8 {
let mut keyid : [u8; 8] = Default::default();
@@ -148,7 +222,21 @@ impl KeyID {
}
}
- /// Returns a reference to the raw KeyID.
+ /// Returns a reference to the raw `KeyID` as a byte slice in big
+ /// endian representation.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use sequoia_openpgp as openpgp;
+ /// use openpgp::KeyID;
+ ///
+ /// # fn main() -> sequoia_openpgp::Result<()> {
+ /// let keyid: KeyID = "0123 4567 89AB CDEF".parse()?;
+ ///
+ /// assert_eq!(keyid.as_bytes(), [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
+ /// # Ok(()) }
+ /// ```
pub fn as_bytes(&self) -> &[u8] {
match self {
&KeyID::V4(ref id) => id,
@@ -156,50 +244,81 @@ impl KeyID {
}
}
- /// Returns the wildcard KeyID.
+ /// Creates a wildcard `KeyID`.
+ ///
+ /// Refer to [Section 5.1 of RFC 4880] for details.
+ ///
+ /// [Section 5.1 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.1
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use sequoia_openpgp as openpgp;
+ /// use openpgp::KeyID;
+ ///
+ /// assert_eq!(KeyID::wildcard(), KeyID::new(0x0000000000000000));
+ /// ```
pub fn wildcard() -> Self {
Self::from_bytes(&[0u8; 8][..])
}
- /// Returns true if this is a wild card ID.
+ /// Returns `true` if this is the wildcard `KeyID`.
+ ///
+ /// Refer to [Section 5.1 of RFC 4880] for details.
+ ///
+ /// [Section 5.1 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.1
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use sequoia_openpgp as openpgp;
+ /// use openpgp::KeyID;
+ ///
+ /// assert!(KeyID::new(0x0000000000000000).is_wildcard());
+ /// ```
pub fn is_wildcard(&self) -> bool {
self.as_bytes().iter().all(|b| *b == 0)
}
- /// Converts this key ID to its canonical hexadecimal representation.
+ /// Converts this `KeyID` to its canonical hexadecimal
+ /// representation.
///
- /// This representation is always uppercase and without spaces and is
- /// suitable for stable key identifiers.
+ /// This representation is always uppercase and without spaces and
+ /// is suitable for stable key identifiers.
///
- /// The output of this function is exactly the same as formatting this
- /// object with the `:X` format specifier.
+ /// The output of this function is exactly the same as formatting
+ /// this object with the `:X` format specifier.
///
/// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
/// # use sequoia_openpgp as openpgp;
/// use openpgp::KeyID;
///
- /// let keyid = "fb3751f1587daef1".parse::<KeyID>().unwrap();
+ /// let keyid: KeyID = "fb3751f1587daef1".parse()?;
///
/// assert_eq!("FB3751F1587DAEF1", keyid.to_hex());
/// assert_eq!(format!("{:X}", keyid), keyid.to_hex());
+ /// # Ok(()) }
/// ```
pub fn to_hex(&self) -> String {
format!("{:X}", self)
}
- /// Parses the hexadecimal representation of an OpenPGP key ID.
+ /// Parses the hexadecimal representation of an OpenPGP `KeyID`.
///
- /// This function is the reverse of `to_hex`. It also accepts other variants
- /// of the key ID notation including lower-case letters, spaces and optional
- /// leading `0x`.
+ /// This function is the reverse of `to_hex`. It also accepts
+ /// other variants of the `keyID` notation including lower-case
+ /// letters, spaces and optional leading `0x`.
///
/// ```rust
+ /// # fn main() -> sequoia_openpgp::Result<()> {
/// # use sequoia_openpgp as openpgp;
/// use openpgp::KeyID;
///
- /// let keyid = KeyID::from_hex("0xfb3751f1587daef1").unwrap();
+ /// let keyid = KeyID::from_hex("0xfb3751f1587daef1")?;
///
/// assert_eq!("FB3751F1587DAEF1", keyid.to_hex());
+ /// # Ok(()) }
/// ```
pub fn from_hex(s: &str) -> std::result::Result<Self, anyhow::Error> {
std::str::FromStr::from_str(s)