From b48597fb18a21adb697de6094d756e5739075055 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 8 May 2020 11:19:13 -0400 Subject: [PATCH] most missing docs for llcrypto --- tor-llcrypto/src/cipher.rs | 3 +++ tor-llcrypto/src/d.rs | 7 ++++-- tor-llcrypto/src/lib.rs | 13 +++++----- tor-llcrypto/src/pk.rs | 7 ++++-- tor-llcrypto/src/pk/keymanip.rs | 20 +++++++++++++--- tor-llcrypto/src/pk/rsa.rs | 42 ++++++++++++++++++++++++++------- 6 files changed, 70 insertions(+), 22 deletions(-) diff --git a/tor-llcrypto/src/cipher.rs b/tor-llcrypto/src/cipher.rs index c23bfec26..78de19924 100644 --- a/tor-llcrypto/src/cipher.rs +++ b/tor-llcrypto/src/cipher.rs @@ -1,4 +1,7 @@ //! Ciphers used to implement the Tor protocols. +//! +//! Fortunately, Tor has managed not to proliferate ciphers. It only +//! uses AES, and (so far) only uses AES in counter mode. /// Re-exports implementations of counter-mode AES pub mod aes { diff --git a/tor-llcrypto/src/d.rs b/tor-llcrypto/src/d.rs index 287e35c2d..42badb222 100644 --- a/tor-llcrypto/src/d.rs +++ b/tor-llcrypto/src/d.rs @@ -3,13 +3,16 @@ //! In various places, for legacy reasons, Tor uses SHA1, SHA2, //! SHA3, and SHAKE. We re-export them all here, implementing //! the Digest trait. +//! +//! Other code should access these digests via the Digest trait. // These implement Digest, so we can just use them as-is. pub use sha2::{Sha256, Sha512}; pub use sha3::{Sha3_256, Shake128, Shake256}; -// The Sha1 crate, OTOH, doesn't expose Digest. I'll do it myself. -/// Wrapper for Sha1 that implements the Digest trait. +/// A Sha1 implementation that implements the Digest trait. +/// +/// (This is just a thin wrapper around the Sha1 crate.) #[derive(Clone, Default)] pub struct Sha1(sha1::Sha1); diff --git a/tor-llcrypto/src/lib.rs b/tor-llcrypto/src/lib.rs index 48e1f7863..1cf4bff3f 100644 --- a/tor-llcrypto/src/lib.rs +++ b/tor-llcrypto/src/lib.rs @@ -1,17 +1,16 @@ //! Low-level crypto implementations for Tor. //! -//! This crate doesn't have anything interesting: it just wraps other -//! crates that implement lower-level cryptographic functionality that -//! Tor does not implement itself. In some cases the functionality is -//! just re-exported; in others, it is wrapped to present a -//! conseistent interface. +//! This crate doesn't have much of interest: for the most part it +//! just wraps other crates that implement lower-level cryptographic +//! functionality. In some cases the functionality is just +//! re-exported; in others, it is wrapped to present a conseistent +//! interface. //! //! Encryption is implemented in `cipher`, digests are in `d`, and //! public key cryptography (including signatures, encryption, and key //! agreement) are in `pk`. -// TODO -- the long-term intention here is that this functionality -// should be replaceable at compile time with other implementations. +#![deny(missing_docs)] pub mod cipher; pub mod d; diff --git a/tor-llcrypto/src/pk.rs b/tor-llcrypto/src/pk.rs index 4eaf284fb..c8c6fc031 100644 --- a/tor-llcrypto/src/pk.rs +++ b/tor-llcrypto/src/pk.rs @@ -1,4 +1,7 @@ -//! Re-exporting public-key cryptography. +//! Public-key cryptography for Tor. +//! +//! In old places, Tor uses RSA; newer Tor public-key cryptography is +//! basd on curve25519 and ed25519. pub mod keymanip; pub mod rsa; @@ -6,7 +9,7 @@ pub mod rsa; /// Re-exporting Curve25519 implementations. /// /// Eventually there should probably be a key-agreement trait or two -/// that this implements, but for now I'm just using the API from +/// that this implements, but for now I'm just re-using the API from /// x25519-dalek. pub mod curve25519 { pub use x25519_dalek::{EphemeralSecret, PublicKey, SharedSecret, StaticSecret}; diff --git a/tor-llcrypto/src/pk/keymanip.rs b/tor-llcrypto/src/pk/keymanip.rs index 22f2c38f6..a76b844c0 100644 --- a/tor-llcrypto/src/pk/keymanip.rs +++ b/tor-llcrypto/src/pk/keymanip.rs @@ -1,3 +1,15 @@ +//! Key manipulation functions for use with public keys. +//! +//! Tor does some interesting and not-really-standard things with its +//! curve25519 and ed25519 keys, for several reasons. +//! +//! In order to prove ownership of a curve25519 private key, Tor +//! converts it into an ed25519 key, and then uses that ed25519 key to +//! sign its identity key. +//! +//! TODO: This is also where we would put the key-derivation code that +//! Tor uses in the hsv3 onion services protocol. + use crate::pk; use digest::Digest; use zeroize::Zeroizing; @@ -7,6 +19,7 @@ use zeroize::Zeroizing; /// /// Note that this formula is not terribly standardized; don't use /// it for anything besides cross-certification. +/// pub fn convert_curve25519_to_ed25519_public( pubkey: &pk::curve25519::PublicKey, signbit: u8, @@ -16,9 +29,10 @@ pub fn convert_curve25519_to_ed25519_public( let point = MontgomeryPoint(*pubkey.as_bytes()); let edpoint = point.to_edwards(signbit)?; - // TODO: This is inefficient; we shouldn't have to re-compress this - // point to get the public key we wanted. But there's no way I - // can to construct an ed25519 public key from a compressed point. + // TODO: This is inefficient; we shouldn't have to re-compress + // this point to get the public key we wanted. But there's no way + // with the current API that I can to construct an ed25519 public + // key from a compressed point. let compressed_y = edpoint.compress(); pk::ed25519::PublicKey::from_bytes(compressed_y.as_bytes()).ok() } diff --git a/tor-llcrypto/src/pk/rsa.rs b/tor-llcrypto/src/pk/rsa.rs index 0a2eda508..e19c75448 100644 --- a/tor-llcrypto/src/pk/rsa.rs +++ b/tor-llcrypto/src/pk/rsa.rs @@ -1,11 +1,13 @@ //! Re-exporting RSA implementations. //! //! This module can currently handle public keys and signature -//! verification as they work in the Tor directory protocol and +//! verification used in the Tor directory protocol and //! similar places. //! //! Currently, that means supporting validating PKCSv1 //! signatures, and encoding and decoding keys from DER. +//! +//! Currently missing is signing and RSA-OEAP. use arrayref::array_ref; use subtle::*; use zeroize::Zeroize; @@ -16,7 +18,7 @@ use zeroize::Zeroize; pub const RSA_ID_LEN: usize = 20; /// An identifier for a Tor relay, based on its legacy RSA -/// identity key. +/// identity key. These are used all over the Tor protocol. #[derive(Clone, Zeroize, Debug)] pub struct RSAIdentity { pub id: [u8; RSA_ID_LEN], @@ -31,9 +33,23 @@ impl PartialEq for RSAIdentity { impl Eq for RSAIdentity {} impl RSAIdentity { + /// Expose and RSAIdentity as a slice of bytes. pub fn as_bytes(&self) -> &[u8] { &self.id[..] } + /// Construct an RSAIdentity from a slice of bytes. + /// + /// Returns None if the input is not of the correct length. + /// + /// ``` + /// let bytes = b"xyzzyxyzzyxyzzyxyzzy"; + /// let id = RSAIdentity::from_bytes(&bytes); + /// assert_eq!(id.unwrap().as_bytes(), bytes); + /// + /// let truncated = b"xyzzy"; + /// let id = RSAIdentity::from_bytes(truncated); + /// assert_eq!(id, None); + /// ``` pub fn from_bytes(bytes: &[u8]) -> Option { if bytes.len() == RSA_ID_LEN { Some(RSAIdentity { @@ -46,11 +62,15 @@ impl RSAIdentity { } /// An RSA public key. +/// +/// This implementation is a simple wrapper so that we can define new +/// methods and traits on the type. pub struct PublicKey(rsa::RSAPublicKey); -/// An RSA Private key. +/// An RSA private key. pub struct PrivateKey(rsa::RSAPrivateKey); impl PrivateKey { + /// Return the public component of this key. pub fn to_public_key(&self) -> PublicKey { PublicKey(self.0.to_public_key()) } @@ -73,16 +93,22 @@ impl PublicKey { /// /// Tor uses RSA-PKCSv1 signatures, with hash algorithm OIDs /// omitted. + /// + /// ## Issues + /// + /// XXXX We probably shouldn't be exposing rsa::errors::Result(). + /// pub fn verify(&self, hashed: &[u8], sig: &[u8]) -> rsa::errors::Result<()> { use rsa::PublicKey; self.0 .verify::(rsa::PaddingScheme::PKCS1v15, None, hashed, sig) - // XXXX I don't want to expose rsa::errors::Result, really. } - /// Decode an alleged DER byte string into a PublicKey. Return None - /// if the DER string does not have a valid PublicKey. + /// Decode an alleged DER byte string into a PublicKey. /// - /// (Does not expect or allow an OID.) + /// Return None if the DER string does not have a valid PublicKey. + /// + /// (This function expects an RSAPublicKey, as used by Tor. It + /// does not expect or accept a PublicKeyInfo.) pub fn from_der(der: &[u8]) -> Option { // We can't use the rsa-der crate, since it expects to find the // key inside of a bitstring inside of another asn1 object. @@ -120,7 +146,7 @@ impl PublicKey { } /// Encode this public key into the DER format as used by Tor. /// - /// Does not attach an OID. + /// The result is an RSAPublicKey, not a PublicKeyInfo. pub fn to_der(&self) -> Vec { use simple_asn1::ASN1Block; // XXX do I really need both of these crates? rsa uses