Upgrade base64 to 0.20

This commit is contained in:
Jonas Platte 2022-12-12 09:21:29 +01:00 committed by Jonas Platte
parent e4678284ca
commit 536341ca7e
5 changed files with 53 additions and 58 deletions

View File

@ -7,7 +7,7 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
assert_matches = "1.5.0" assert_matches = "1.5.0"
assign = "1.1.1" assign = "1.1.1"
base64 = "0.13.1" base64 = "0.20.0"
criterion = "0.4.0" criterion = "0.4.0"
http = "0.2.8" http = "0.2.8"
js_int = "0.2.2" js_int = "0.2.2"

View File

@ -2,6 +2,7 @@
use std::{fmt, marker::PhantomData}; use std::{fmt, marker::PhantomData};
use base64::engine::fast_portable::{self, FastPortable, FastPortableConfig};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
/// A wrapper around `B` (usually `Vec<u8>`) that (de)serializes from / to a base64 string. /// A wrapper around `B` (usually `Vec<u8>`) that (de)serializes from / to a base64 string.
@ -25,7 +26,7 @@ pub trait Base64Config {
} }
#[doc(hidden)] #[doc(hidden)]
pub struct Conf(base64::Config); pub struct Conf(base64::alphabet::Alphabet);
/// Standard base64 character set without padding. /// Standard base64 character set without padding.
/// ///
@ -36,8 +37,7 @@ pub struct Conf(base64::Config);
pub struct Standard; pub struct Standard;
impl Base64Config for Standard { impl Base64Config for Standard {
// See https://github.com/matrix-org/matrix-spec/issues/838 const CONF: Conf = Conf(base64::alphabet::STANDARD);
const CONF: Conf = Conf(base64::STANDARD_NO_PAD.decode_allow_trailing_bits(true));
} }
/// Url-safe base64 character set without padding. /// Url-safe base64 character set without padding.
@ -49,7 +49,13 @@ impl Base64Config for Standard {
pub struct UrlSafe; pub struct UrlSafe;
impl Base64Config for UrlSafe { impl Base64Config for UrlSafe {
const CONF: Conf = Conf(base64::URL_SAFE_NO_PAD.decode_allow_trailing_bits(true)); const CONF: Conf = Conf(base64::alphabet::URL_SAFE);
}
impl<C: Base64Config, B> Base64<C, B> {
// See https://github.com/matrix-org/matrix-spec/issues/838
const CONFIG: FastPortableConfig = fast_portable::NO_PAD.with_decode_allow_trailing_bits(true);
const ENGINE: FastPortable = FastPortable::from(&C::CONF.0, Self::CONFIG);
} }
impl<C: Base64Config, B: AsRef<[u8]>> Base64<C, B> { impl<C: Base64Config, B: AsRef<[u8]>> Base64<C, B> {
@ -65,7 +71,7 @@ impl<C: Base64Config, B: AsRef<[u8]>> Base64<C, B> {
/// Encode the bytes contained in this `Base64` instance to unpadded base64. /// Encode the bytes contained in this `Base64` instance to unpadded base64.
pub fn encode(&self) -> String { pub fn encode(&self) -> String {
base64::encode_config(&self.bytes, C::CONF.0) base64::encode_engine(self.as_bytes(), &Self::ENGINE)
} }
} }
@ -84,7 +90,7 @@ impl<C: Base64Config> Base64<C> {
/// Parse some base64-encoded data to create a `Base64` instance. /// Parse some base64-encoded data to create a `Base64` instance.
pub fn parse(encoded: impl AsRef<[u8]>) -> Result<Self, Base64DecodeError> { pub fn parse(encoded: impl AsRef<[u8]>) -> Result<Self, Base64DecodeError> {
base64::decode_config(encoded, C::CONF.0).map(Self::new).map_err(Base64DecodeError) base64::decode_engine(encoded, &Self::ENGINE).map(Self::new).map_err(Base64DecodeError)
} }
} }

View File

@ -6,7 +6,7 @@ use std::{
mem, mem,
}; };
use base64::{encode_config, STANDARD_NO_PAD, URL_SAFE_NO_PAD}; use base64::{alphabet, encode_engine};
use ruma_common::{ use ruma_common::{
canonical_json::{redact, JsonType}, canonical_json::{redact, JsonType},
serde::{base64::Standard, Base64}, serde::{base64::Standard, Base64},
@ -55,16 +55,18 @@ static REFERENCE_HASH_FIELDS_TO_REMOVE: &[&str] = &["age_ts", "signatures", "uns
/// A homeserver signs JSON with a key pair: /// A homeserver signs JSON with a key pair:
/// ///
/// ```rust /// ```rust
/// # use ruma_common::serde::base64::Base64;
/// #
/// const PKCS8: &str = "\ /// const PKCS8: &str = "\
/// MFECAQEwBQYDK2VwBCIEINjozvdfbsGEt6DD+7Uf4PiJ/YvTNXV2mIPc/\ /// MFECAQEwBQYDK2VwBCIEINjozvdfbsGEt6DD+7Uf4PiJ/YvTNXV2mIPc/\
/// tA0T+6tgSEA3TPraTczVkDPTRaX4K+AfUuyx7Mzq1UafTXypnl0t2k=\ /// tA0T+6tgSEA3TPraTczVkDPTRaX4K+AfUuyx7Mzq1UafTXypnl0t2k\
/// "; /// ";
/// ///
/// let document = base64::decode_config(&PKCS8, base64::STANDARD_NO_PAD).unwrap(); /// let document: Base64 = Base64::parse(PKCS8).unwrap();
/// ///
/// // Create an Ed25519 key pair. /// // Create an Ed25519 key pair.
/// let key_pair = ruma_signatures::Ed25519KeyPair::from_der( /// let key_pair = ruma_signatures::Ed25519KeyPair::from_der(
/// &document, /// document.as_bytes(),
/// "1".into(), // The "version" of the key. /// "1".into(), // The "version" of the key.
/// ) /// )
/// .unwrap(); /// .unwrap();
@ -331,14 +333,17 @@ pub fn reference_hash(
let hash = Sha256::digest(json.as_bytes()); let hash = Sha256::digest(json.as_bytes());
Ok(encode_config( let base64_alphabet = match version {
hash, RoomVersionId::V1 | RoomVersionId::V2 | RoomVersionId::V3 => alphabet::STANDARD,
match version { // Room versions higher than version 3 are url safe base64 encoded
RoomVersionId::V1 | RoomVersionId::V2 | RoomVersionId::V3 => STANDARD_NO_PAD, _ => alphabet::URL_SAFE,
// Room versions higher than version 3 are url safe base64 encoded };
_ => URL_SAFE_NO_PAD, let base64_engine = base64::engine::fast_portable::FastPortable::from(
}, &base64_alphabet,
)) base64::engine::fast_portable::NO_PAD,
);
Ok(encode_engine(hash, &base64_engine))
} }
/// Hashes and signs an event and adds the hash and signature to objects under the keys `hashes` and /// Hashes and signs an event and adds the hash and signature to objects under the keys `hashes` and
@ -366,19 +371,19 @@ pub fn reference_hash(
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// # use ruma_common::RoomVersionId; /// # use ruma_common::{RoomVersionId, serde::base64::Base64};
/// # use ruma_signatures::{hash_and_sign_event, Ed25519KeyPair}; /// # use ruma_signatures::{hash_and_sign_event, Ed25519KeyPair};
/// # /// #
/// const PKCS8: &str = "\ /// const PKCS8: &str = "\
/// MFECAQEwBQYDK2VwBCIEINjozvdfbsGEt6DD+7Uf4PiJ/YvTNXV2mIPc/\ /// MFECAQEwBQYDK2VwBCIEINjozvdfbsGEt6DD+7Uf4PiJ/YvTNXV2mIPc/\
/// tA0T+6tgSEA3TPraTczVkDPTRaX4K+AfUuyx7Mzq1UafTXypnl0t2k=\ /// tA0T+6tgSEA3TPraTczVkDPTRaX4K+AfUuyx7Mzq1UafTXypnl0t2k\
/// "; /// ";
/// ///
/// let document = base64::decode_config(&PKCS8, base64::STANDARD_NO_PAD).unwrap(); /// let document: Base64 = Base64::parse(PKCS8).unwrap();
/// ///
/// // Create an Ed25519 key pair. /// // Create an Ed25519 key pair.
/// let key_pair = Ed25519KeyPair::from_der( /// let key_pair = Ed25519KeyPair::from_der(
/// &document, /// document.as_bytes(),
/// "1".into(), // The "version" of the key. /// "1".into(), // The "version" of the key.
/// ) /// )
/// .unwrap(); /// .unwrap();

View File

@ -103,29 +103,29 @@ fn split_id(id: &str) -> Result<(Algorithm, String), Error> {
mod tests { mod tests {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use base64::{decode_config, STANDARD_NO_PAD};
use pkcs8::{der::Decode, PrivateKeyInfo}; use pkcs8::{der::Decode, PrivateKeyInfo};
use ruma_common::{serde::Base64, RoomVersionId}; use ruma_common::{
serde::{base64::Standard, Base64},
RoomVersionId,
};
use serde_json::{from_str as from_json_str, to_string as to_json_string}; use serde_json::{from_str as from_json_str, to_string as to_json_string};
use super::{ use super::{
canonical_json, hash_and_sign_event, sign_json, verify_event, verify_json, Ed25519KeyPair, canonical_json, hash_and_sign_event, sign_json, verify_event, verify_json, Ed25519KeyPair,
}; };
const PKCS8: &str = "\ fn pkcs8() -> Vec<u8> {
MFECAQEwBQYDK2VwBCIEINjozvdfbsGEt6DD+7Uf4PiJ/YvTNXV2mIPc/\ const ENCODED: &str = "\
tA0T+6tgSEA3TPraTczVkDPTRaX4K+AfUuyx7Mzq1UafTXypnl0t2k=\ MFECAQEwBQYDK2VwBCIEINjozvdfbsGEt6DD+7Uf4PiJ/YvTNXV2mIPc/\
"; tA0T+6tgSEA3TPraTczVkDPTRaX4K+AfUuyx7Mzq1UafTXypnl0t2k\
";
Base64::<Standard>::parse(ENCODED).unwrap().into_inner()
}
/// Convenience method for getting the public key as a string /// Convenience method for getting the public key as a string
fn public_key_string() -> Base64 { fn public_key_string() -> Base64 {
Base64::new( Base64::new(PrivateKeyInfo::from_der(&pkcs8()).unwrap().public_key.unwrap().to_owned())
PrivateKeyInfo::from_der(&decode_config(PKCS8, STANDARD_NO_PAD).unwrap())
.unwrap()
.public_key
.unwrap()
.to_owned(),
)
} }
/// Convenience for converting a string of JSON into its canonical form. /// Convenience for converting a string of JSON into its canonical form.
@ -225,11 +225,7 @@ mod tests {
#[test] #[test]
fn sign_empty_json() { fn sign_empty_json() {
let key_pair = Ed25519KeyPair::from_der( let key_pair = Ed25519KeyPair::from_der(&pkcs8(), "1".into()).unwrap();
decode_config(PKCS8, STANDARD_NO_PAD).unwrap().as_slice(),
"1".into(),
)
.unwrap();
let mut value = from_json_str("{}").unwrap(); let mut value = from_json_str("{}").unwrap();
@ -256,11 +252,7 @@ mod tests {
#[test] #[test]
fn sign_minimal_json() { fn sign_minimal_json() {
let key_pair = Ed25519KeyPair::from_der( let key_pair = Ed25519KeyPair::from_der(&pkcs8(), "1".into()).unwrap();
decode_config(PKCS8, STANDARD_NO_PAD).unwrap().as_slice(),
"1".into(),
)
.unwrap();
let mut alpha_object = from_json_str(r#"{ "one": 1, "two": "Two" }"#).unwrap(); let mut alpha_object = from_json_str(r#"{ "one": 1, "two": "Two" }"#).unwrap();
sign_json("domain", &key_pair, &mut alpha_object).unwrap(); sign_json("domain", &key_pair, &mut alpha_object).unwrap();
@ -316,11 +308,7 @@ mod tests {
#[test] #[test]
fn sign_minimal_event() { fn sign_minimal_event() {
let key_pair = Ed25519KeyPair::from_der( let key_pair = Ed25519KeyPair::from_der(&pkcs8(), "1".into()).unwrap();
decode_config(PKCS8, STANDARD_NO_PAD).unwrap().as_slice(),
"1".into(),
)
.unwrap();
let json = r#"{ let json = r#"{
"room_id": "!x:domain", "room_id": "!x:domain",
@ -350,11 +338,7 @@ mod tests {
#[test] #[test]
fn sign_redacted_event() { fn sign_redacted_event() {
let key_pair = Ed25519KeyPair::from_der( let key_pair = Ed25519KeyPair::from_der(&pkcs8(), "1".into()).unwrap();
decode_config(PKCS8, STANDARD_NO_PAD).unwrap().as_slice(),
"1".into(),
)
.unwrap();
let json = r#"{ let json = r#"{
"content": { "content": {

View File

@ -1,6 +1,6 @@
//! Digital signatures and collections of signatures. //! Digital signatures and collections of signatures.
use base64::{encode_config, STANDARD_NO_PAD}; use ruma_common::serde::{base64::Standard, Base64};
use crate::{split_id, Algorithm, Error}; use crate::{split_id, Algorithm, Error};
@ -61,7 +61,7 @@ impl Signature {
/// ///
/// Uses the standard character set with no padding. /// Uses the standard character set with no padding.
pub fn base64(&self) -> String { pub fn base64(&self) -> String {
encode_config(self.signature.as_slice(), STANDARD_NO_PAD) Base64::<Standard, _>::new(self.signature.as_slice()).encode()
} }
/// The key identifier, a string containing the signature algorithm and the key "version" /// The key identifier, a string containing the signature algorithm and the key "version"