diff --git a/.github/workflows/crypto-bigint.yml b/.github/workflows/crypto-bigint.yml index 22a031d2..ddd823d9 100644 --- a/.github/workflows/crypto-bigint.yml +++ b/.github/workflows/crypto-bigint.yml @@ -34,11 +34,12 @@ jobs: override: true - run: cargo build --target ${{ matrix.target }} --release --no-default-features - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc + - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features der - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features generic-array - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rand_core - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rlp - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features zeroize - - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,generic-array,rand_core,rlp,zeroize + - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,der,generic-array,rand_core,rlp,zeroize test: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 933fa4bd..7eacef56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,6 +51,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "crypto-bigint" version = "0.4.0-pre" dependencies = [ + "der", "generic-array", "hex-literal", "num-bigint", @@ -63,6 +64,11 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der" +version = "0.6.0-pre" +source = "git+https://github.com/RustCrypto/formats.git#86f682491d0534126f70fdc9f5312e483323f862" + [[package]] name = "fnv" version = "1.0.7" diff --git a/Cargo.toml b/Cargo.toml index bd400c9b..dc182778 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ rust-version = "1.57" subtle = { version = "2.4", default-features = false } # optional dependencies +der = { version = "=0.6.0-pre", optional = true, default-features = false } generic-array = { version = "0.14", optional = true } rand_core = { version = "0.6", optional = true } rlp = { version = "0.5", optional = true, default-features = false } @@ -41,3 +42,6 @@ rand = ["rand_core/std"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] + +[patch.crates-io] +der = { git = "https://github.com/RustCrypto/formats.git" } diff --git a/src/uint/encoding.rs b/src/uint/encoding.rs index 0af38315..710d056e 100644 --- a/src/uint/encoding.rs +++ b/src/uint/encoding.rs @@ -2,6 +2,9 @@ mod decoder; +#[cfg(all(feature = "der", feature = "generic-array"))] +mod der; + #[cfg(feature = "rlp")] mod rlp; diff --git a/src/uint/encoding/der.rs b/src/uint/encoding/der.rs new file mode 100644 index 00000000..847a5384 --- /dev/null +++ b/src/uint/encoding/der.rs @@ -0,0 +1,63 @@ +//! Support for decoding/encoding [`UInt`] as an ASN.1 DER `INTEGER`. + +use crate::{generic_array::GenericArray, ArrayEncoding, UInt}; +use ::der::{ + asn1::{Any, UIntBytes}, + EncodeValue, Encoder, FixedTag, Length, Tag, +}; + +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl<'a, const LIMBS: usize> TryFrom> for UInt +where + UInt: ArrayEncoding, +{ + type Error = der::Error; + + fn try_from(any: Any<'a>) -> der::Result> { + UIntBytes::try_from(any)?.try_into() + } +} + +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl<'a, const LIMBS: usize> TryFrom> for UInt +where + UInt: ArrayEncoding, +{ + type Error = der::Error; + + fn try_from(bytes: UIntBytes<'a>) -> der::Result> { + let mut array = GenericArray::default(); + let offset = array.len().saturating_sub(bytes.len().try_into()?); + array[offset..].copy_from_slice(bytes.as_bytes()); + Ok(UInt::from_be_byte_array(array)) + } +} + +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl EncodeValue for UInt +where + UInt: ArrayEncoding, +{ + fn value_len(&self) -> der::Result { + // TODO(tarcieri): more efficient length calculation + let array = self.to_be_byte_array(); + UIntBytes::new(&array)?.value_len() + } + + fn encode_value(&self, encoder: &mut Encoder<'_>) -> der::Result<()> { + let array = self.to_be_byte_array(); + UIntBytes::new(&array)?.encode_value(encoder) + } +} + +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl FixedTag for UInt +where + UInt: ArrayEncoding, +{ + const TAG: Tag = Tag::Integer; +}