asn1_len

Crates.ioasn1_len
lib.rsasn1_len
version2.0.0
created_at2025-08-17 11:36:48.515808+00
updated_at2025-09-08 08:12:22.127264+00
descriptionA utilities to convert back and forth between unsigned int and ASN.1 Length.
homepage
repositoryhttps://github.com/NattapongSiri/asn1_len_rs
max_upload_size
id1799345
size50,242
(NattapongSiri)

documentation

README

asn1_len

A crate that allow transformation between ASN.1 Length object and various unsigned int types.

Supported features

This crate provides following feature gates:

  • primitive - Provides Asn1Len struct and the way to convert back and forth with primitive type.
  • bigint - Similar to primitve with additional support for convert back and forth with crypto_bigint::Uint and crypto_bigint::BoxedUint.
  • macro - Provides a utility function value_def which is a helper function to encode ASN.1 Length value from LitInt.
  • full - All above features are enabled.

The default feature is primitive.

How to install

To use with standard Rust unsigned integer type:

cargo add asn1_len

To use with big unsigned integer:

cargo add asn1_len --features bigint

To use macro helper function:

cargo add asn1_len --features macro

To enable all features:

cargo add asn1_len --features full

macro feature - Compile time ASN.1 Length declaration

With feature gate macro, This crate provides value_def helper function to parse/tranform LitInt when dealing with procedural macro. The function return tuple of (TokenStream, usize).

The TokenStream contains a comma separated value of LitInt which conform to ASN.1 format. Each LitInt is a byte. If there're more than one byte, the first byte is encoded length of the length itself. See this wiki for how it encode the length.

The usize contains a number of LitInt inside the TokenStream including the encoded length byte.

It is mandatory that the procedural macro that make use of this function must produce a complete valid syntax of Rust.

Example

Build fixed size array of ASN.1 Length

let (token, size) = asn1_len::value_def!(128);
quote! { [#token; #size] } // Build a fixed size array of ASN.1 Length

Runtime ASN.1 Length declaration

With feature gate primitive, This crate provides struct Asn1Len. The struct provides method with_header and without_header. with_header returns a slice contains a complete byte sequence including an encoded length of the length itself. See this wiki for how it encode the length. . without_header simply return length value encoded as big-endian byte sequence. The only different between the two is the first byte. without_header excludes the first byte of with_header method.

To construct Asn1Len, there are 3 methods.

With feature gate primitive, or bigint:

  • Asn1Len::from_primitive or Asn1Len::from using std::convert::From trait. It allow any of Rust unsigned integer primitive to be convert into Asn1Len.

Only with feature gate bigint:

  • Asn1Len::from_big_uint method to create an encoded ASN.1 Length out of given Uint object.
  • Asn1Len::from_boxed_big_uint method to create an encoded ASN.1 Length out of given BoxedUint object.

Only Asn1Len::from_primitive guarantee to return Asn1Len. The others return Result which if value is too big to be encoded into ASN.1 Length, it return OverflowError.

To work with Asn1Len, this required a convert back from Asn1Len object into some kind of workable type such as Rust primitive data type or those of Uint variants. This crate provide 3 methods.

This method available on both feature bigint and primitive:

  • Asn1Len::to_primitive. It allow a conversion to one of unsigned integer type of Rust. If value cannot be fit into such type, it return OverflowError.

These methods available onfeature bigint only:

  • Asn1Len::to_big_uint. It allow a conversion to crypto_bigint::Uint type. If the LIMB specified is not large enough to accommodate current ASN.1 Length, it return OverflowError.
  • Asn1Len::to_boxed_big_uint. It allow a conversion to crypto_bigint::BoxedUint type.

Only Asn1Len::to_boxed_big_uint guarantee to return BoxedUint. The others return Result which if value is too big to be accommodate to target type, it return OverflowError.

Example

use asn1_len::Asn1Len;
let len = Asn1Len::from_primitive(1u8);
assert_eq!(len.with_header(), &[1u8]);
let new_len = Asn1Len::from_primitive(len.to_primitive::<u16>().unwrap() + 255);
assert_eq!(new_len.with_header(), &[0x82u8, 0x01, 0x00]);
new_len.to_primitive::<u8>().unwrap_err(); // Value too large to fit into u8
let big_len = Asn1Len::from_big_uint(&crypto_bigint::Uint::<{127 / crypto_bigint::Limb::BYTES as usize}>::MAX).unwrap();
big_len.to_big_uint::<1>().unwrap_err(); // Value too large to fit into this Uint with 1 limb
let variable_len = big_len.to_boxed_big_uint().widen(4096); // Make 4096 bits with value from previous big_len
variable_len.checked_add(&Uint::<32>::MAX.into()).unwrap();

// Make largest possible length in ASN.1 Length specification
let mut max_len: [u8; 128] = [0xFF; 128];
max_len[0] = 0;
max_len[1] = 0;
let max_val = crypto_bigint::Uint::<{128 / Limb::BYTES as usize}>::from_be_bytes(max_len);
Asn1Len::from_big_uint(&max_val).unwrap(); // it should succeed.
let overflow_val = max_val.checked_add(&Uint::ONE).unwrap(); // Add 1 to max_len 
Asn1Len::from_big_uint(&overflow_val).unwrap_err(); // It should overflow when turn it into ASN.1 Length

What's new

2.0.0

Breaking change

Split library into 3 main features. The default features is primitive. The equivalence to version 1.x.x is full.

Migrate from 1.x.x

cargo add asn1_len --features full

1.1.0

Asn1Len now implements PartialEq, Eq, PartialOrd, and Ord

Commit count: 6

cargo fmt