most missing docs for llcrypto

This commit is contained in:
Nick Mathewson 2020-05-08 11:19:13 -04:00
parent 3c7f75302b
commit b48597fb18
6 changed files with 70 additions and 22 deletions

View File

@ -1,4 +1,7 @@
//! Ciphers used to implement the Tor protocols. //! 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 /// Re-exports implementations of counter-mode AES
pub mod aes { pub mod aes {

View File

@ -3,13 +3,16 @@
//! In various places, for legacy reasons, Tor uses SHA1, SHA2, //! In various places, for legacy reasons, Tor uses SHA1, SHA2,
//! SHA3, and SHAKE. We re-export them all here, implementing //! SHA3, and SHAKE. We re-export them all here, implementing
//! the Digest trait. //! the Digest trait.
//!
//! Other code should access these digests via the Digest trait.
// These implement Digest, so we can just use them as-is. // These implement Digest, so we can just use them as-is.
pub use sha2::{Sha256, Sha512}; pub use sha2::{Sha256, Sha512};
pub use sha3::{Sha3_256, Shake128, Shake256}; pub use sha3::{Sha3_256, Shake128, Shake256};
// The Sha1 crate, OTOH, doesn't expose Digest. I'll do it myself. /// A Sha1 implementation that implements the Digest trait.
/// Wrapper for Sha1 that implements the Digest trait. ///
/// (This is just a thin wrapper around the Sha1 crate.)
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Sha1(sha1::Sha1); pub struct Sha1(sha1::Sha1);

View File

@ -1,17 +1,16 @@
//! Low-level crypto implementations for Tor. //! Low-level crypto implementations for Tor.
//! //!
//! This crate doesn't have anything interesting: it just wraps other //! This crate doesn't have much of interest: for the most part it
//! crates that implement lower-level cryptographic functionality that //! just wraps other crates that implement lower-level cryptographic
//! Tor does not implement itself. In some cases the functionality is //! functionality. In some cases the functionality is just
//! just re-exported; in others, it is wrapped to present a //! re-exported; in others, it is wrapped to present a conseistent
//! conseistent interface. //! interface.
//! //!
//! Encryption is implemented in `cipher`, digests are in `d`, and //! Encryption is implemented in `cipher`, digests are in `d`, and
//! public key cryptography (including signatures, encryption, and key //! public key cryptography (including signatures, encryption, and key
//! agreement) are in `pk`. //! agreement) are in `pk`.
// TODO -- the long-term intention here is that this functionality #![deny(missing_docs)]
// should be replaceable at compile time with other implementations.
pub mod cipher; pub mod cipher;
pub mod d; pub mod d;

View File

@ -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 keymanip;
pub mod rsa; pub mod rsa;
@ -6,7 +9,7 @@ pub mod rsa;
/// Re-exporting Curve25519 implementations. /// Re-exporting Curve25519 implementations.
/// ///
/// Eventually there should probably be a key-agreement trait or two /// 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. /// x25519-dalek.
pub mod curve25519 { pub mod curve25519 {
pub use x25519_dalek::{EphemeralSecret, PublicKey, SharedSecret, StaticSecret}; pub use x25519_dalek::{EphemeralSecret, PublicKey, SharedSecret, StaticSecret};

View File

@ -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 crate::pk;
use digest::Digest; use digest::Digest;
use zeroize::Zeroizing; use zeroize::Zeroizing;
@ -7,6 +19,7 @@ use zeroize::Zeroizing;
/// ///
/// Note that this formula is not terribly standardized; don't use /// Note that this formula is not terribly standardized; don't use
/// it for anything besides cross-certification. /// it for anything besides cross-certification.
///
pub fn convert_curve25519_to_ed25519_public( pub fn convert_curve25519_to_ed25519_public(
pubkey: &pk::curve25519::PublicKey, pubkey: &pk::curve25519::PublicKey,
signbit: u8, signbit: u8,
@ -16,9 +29,10 @@ pub fn convert_curve25519_to_ed25519_public(
let point = MontgomeryPoint(*pubkey.as_bytes()); let point = MontgomeryPoint(*pubkey.as_bytes());
let edpoint = point.to_edwards(signbit)?; let edpoint = point.to_edwards(signbit)?;
// TODO: This is inefficient; we shouldn't have to re-compress this // TODO: This is inefficient; we shouldn't have to re-compress
// point to get the public key we wanted. But there's no way I // this point to get the public key we wanted. But there's no way
// can to construct an ed25519 public key from a compressed point. // with the current API that I can to construct an ed25519 public
// key from a compressed point.
let compressed_y = edpoint.compress(); let compressed_y = edpoint.compress();
pk::ed25519::PublicKey::from_bytes(compressed_y.as_bytes()).ok() pk::ed25519::PublicKey::from_bytes(compressed_y.as_bytes()).ok()
} }

View File

@ -1,11 +1,13 @@
//! Re-exporting RSA implementations. //! Re-exporting RSA implementations.
//! //!
//! This module can currently handle public keys and signature //! 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. //! similar places.
//! //!
//! Currently, that means supporting validating PKCSv1 //! Currently, that means supporting validating PKCSv1
//! signatures, and encoding and decoding keys from DER. //! signatures, and encoding and decoding keys from DER.
//!
//! Currently missing is signing and RSA-OEAP.
use arrayref::array_ref; use arrayref::array_ref;
use subtle::*; use subtle::*;
use zeroize::Zeroize; use zeroize::Zeroize;
@ -16,7 +18,7 @@ use zeroize::Zeroize;
pub const RSA_ID_LEN: usize = 20; pub const RSA_ID_LEN: usize = 20;
/// An identifier for a Tor relay, based on its legacy RSA /// 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)] #[derive(Clone, Zeroize, Debug)]
pub struct RSAIdentity { pub struct RSAIdentity {
pub id: [u8; RSA_ID_LEN], pub id: [u8; RSA_ID_LEN],
@ -31,9 +33,23 @@ impl PartialEq<RSAIdentity> for RSAIdentity {
impl Eq for RSAIdentity {} impl Eq for RSAIdentity {}
impl RSAIdentity { impl RSAIdentity {
/// Expose and RSAIdentity as a slice of bytes.
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
&self.id[..] &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<Self> { pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() == RSA_ID_LEN { if bytes.len() == RSA_ID_LEN {
Some(RSAIdentity { Some(RSAIdentity {
@ -46,11 +62,15 @@ impl RSAIdentity {
} }
/// An RSA public key. /// 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); pub struct PublicKey(rsa::RSAPublicKey);
/// An RSA Private key. /// An RSA private key.
pub struct PrivateKey(rsa::RSAPrivateKey); pub struct PrivateKey(rsa::RSAPrivateKey);
impl PrivateKey { impl PrivateKey {
/// Return the public component of this key.
pub fn to_public_key(&self) -> PublicKey { pub fn to_public_key(&self) -> PublicKey {
PublicKey(self.0.to_public_key()) PublicKey(self.0.to_public_key())
} }
@ -73,16 +93,22 @@ impl PublicKey {
/// ///
/// Tor uses RSA-PKCSv1 signatures, with hash algorithm OIDs /// Tor uses RSA-PKCSv1 signatures, with hash algorithm OIDs
/// omitted. /// omitted.
///
/// ## Issues
///
/// XXXX We probably shouldn't be exposing rsa::errors::Result().
///
pub fn verify(&self, hashed: &[u8], sig: &[u8]) -> rsa::errors::Result<()> { pub fn verify(&self, hashed: &[u8], sig: &[u8]) -> rsa::errors::Result<()> {
use rsa::PublicKey; use rsa::PublicKey;
self.0 self.0
.verify::<rsa::hash::Hashes>(rsa::PaddingScheme::PKCS1v15, None, hashed, sig) .verify::<rsa::hash::Hashes>(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 /// Decode an alleged DER byte string into a PublicKey.
/// if the DER string does not have a valid 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<Self> { pub fn from_der(der: &[u8]) -> Option<Self> {
// We can't use the rsa-der crate, since it expects to find the // We can't use the rsa-der crate, since it expects to find the
// key inside of a bitstring inside of another asn1 object. // 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. /// 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<u8> { pub fn to_der(&self) -> Vec<u8> {
use simple_asn1::ASN1Block; use simple_asn1::ASN1Block;
// XXX do I really need both of these crates? rsa uses // XXX do I really need both of these crates? rsa uses