pub const fn encoded_len(arcs: &[u32]) -> usize {
assert!(arcs.len() >= 2, "OID must have at least 2 arcs");
assert!(arcs[0] <= 2, "OID first arc must be 0, 1, or 2");
if arcs[0] < 2 {
assert!(
arcs[1] < 40,
"OID second arc must be < 40 when first arc < 2"
);
}
let mut len = 1; let mut i = 2;
while i < arcs.len() {
let mut bytes = 1u32;
let mut x = arcs[i] >> 7;
while x > 0 {
bytes += 1;
x >>= 7;
}
len += bytes as usize;
i += 1;
}
len
}
#[allow(clippy::cast_possible_truncation)]
pub const fn encode<const LEN: usize>(arcs: &[u32]) -> [u8; LEN] {
let mut out = [0u8; LEN];
out[0] = (40 * arcs[0] + arcs[1]) as u8;
let mut pos = 1usize;
let mut i = 2;
while i < arcs.len() {
let arc = arcs[i];
let mut bytes_needed = 1u32;
let mut tmp = arc >> 7;
while tmp > 0 {
bytes_needed += 1;
tmp >>= 7;
}
let mut j = bytes_needed;
while j > 0 {
j -= 1;
let shift = j * 7;
let chunk = ((arc >> shift) & 0x7F) as u8;
let cont = if j == 0 { 0u8 } else { 0x80u8 };
out[pos] = chunk | cont;
pos += 1;
}
i += 1;
}
out
}
const ARCS_ID_EC_PUBLIC_KEY: &[u32] = &[1, 2, 840, 10045, 2, 1];
const LEN_ID_EC_PUBLIC_KEY: usize = encoded_len(ARCS_ID_EC_PUBLIC_KEY);
const ENCODED_ID_EC_PUBLIC_KEY: [u8; LEN_ID_EC_PUBLIC_KEY] =
encode::<LEN_ID_EC_PUBLIC_KEY>(ARCS_ID_EC_PUBLIC_KEY);
pub const ID_EC_PUBLIC_KEY: &[u8] = &ENCODED_ID_EC_PUBLIC_KEY;
const ARCS_SM2P256V1: &[u32] = &[1, 2, 156, 10197, 1, 301];
const LEN_SM2P256V1: usize = encoded_len(ARCS_SM2P256V1);
const ENCODED_SM2P256V1: [u8; LEN_SM2P256V1] = encode::<LEN_SM2P256V1>(ARCS_SM2P256V1);
pub const SM2P256V1: &[u8] = &ENCODED_SM2P256V1;
const ARCS_SM2_SIGN_WITH_SM3: &[u32] = &[1, 2, 156, 10197, 1, 501];
const LEN_SM2_SIGN_WITH_SM3: usize = encoded_len(ARCS_SM2_SIGN_WITH_SM3);
const ENCODED_SM2_SIGN_WITH_SM3: [u8; LEN_SM2_SIGN_WITH_SM3] =
encode::<LEN_SM2_SIGN_WITH_SM3>(ARCS_SM2_SIGN_WITH_SM3);
pub const SM2_SIGN_WITH_SM3: &[u8] = &ENCODED_SM2_SIGN_WITH_SM3;
const ARCS_ID_PBKDF2: &[u32] = &[1, 2, 840, 113_549, 1, 5, 12];
const LEN_ID_PBKDF2: usize = encoded_len(ARCS_ID_PBKDF2);
const ENCODED_ID_PBKDF2: [u8; LEN_ID_PBKDF2] = encode::<LEN_ID_PBKDF2>(ARCS_ID_PBKDF2);
pub const ID_PBKDF2: &[u8] = &ENCODED_ID_PBKDF2;
const ARCS_PBES2: &[u32] = &[1, 2, 840, 113_549, 1, 5, 13];
const LEN_PBES2: usize = encoded_len(ARCS_PBES2);
const ENCODED_PBES2: [u8; LEN_PBES2] = encode::<LEN_PBES2>(ARCS_PBES2);
pub const PBES2: &[u8] = &ENCODED_PBES2;
const ARCS_ID_HMAC_WITH_SM3: &[u32] = &[1, 2, 156, 10197, 1, 401, 2];
const LEN_ID_HMAC_WITH_SM3: usize = encoded_len(ARCS_ID_HMAC_WITH_SM3);
const ENCODED_ID_HMAC_WITH_SM3: [u8; LEN_ID_HMAC_WITH_SM3] =
encode::<LEN_ID_HMAC_WITH_SM3>(ARCS_ID_HMAC_WITH_SM3);
pub const ID_HMAC_WITH_SM3: &[u8] = &ENCODED_ID_HMAC_WITH_SM3;
const ARCS_SM4_CBC: &[u32] = &[1, 2, 156, 10197, 1, 104, 2];
const LEN_SM4_CBC: usize = encoded_len(ARCS_SM4_CBC);
const ENCODED_SM4_CBC: [u8; LEN_SM4_CBC] = encode::<LEN_SM4_CBC>(ARCS_SM4_CBC);
pub const SM4_CBC: &[u8] = &ENCODED_SM4_CBC;
#[cfg(test)]
mod tests {
use super::*;
fn runtime_encode(arcs: &[u32]) -> alloc::vec::Vec<u8> {
let mut out = alloc::vec::Vec::new();
#[allow(clippy::cast_possible_truncation)]
out.push((40 * arcs[0] + arcs[1]) as u8);
for &arc in &arcs[2..] {
let mut bytes_needed = 1u32;
let mut tmp = arc >> 7;
while tmp > 0 {
bytes_needed += 1;
tmp >>= 7;
}
for j in (0..bytes_needed).rev() {
let shift = j * 7;
#[allow(clippy::cast_possible_truncation)]
let chunk = ((arc >> shift) & 0x7F) as u8;
let cont = if j == 0 { 0u8 } else { 0x80u8 };
out.push(chunk | cont);
}
}
out
}
#[test]
fn const_matches_runtime_id_ec_public_key() {
assert_eq!(
ID_EC_PUBLIC_KEY,
runtime_encode(ARCS_ID_EC_PUBLIC_KEY).as_slice()
);
}
#[test]
fn const_matches_runtime_sm2p256v1() {
assert_eq!(SM2P256V1, runtime_encode(ARCS_SM2P256V1).as_slice());
}
#[test]
fn const_matches_runtime_sm2_sign_with_sm3() {
assert_eq!(
SM2_SIGN_WITH_SM3,
runtime_encode(ARCS_SM2_SIGN_WITH_SM3).as_slice()
);
}
#[test]
fn const_matches_runtime_id_pbkdf2() {
assert_eq!(ID_PBKDF2, runtime_encode(ARCS_ID_PBKDF2).as_slice());
}
#[test]
fn const_matches_runtime_pbes2() {
assert_eq!(PBES2, runtime_encode(ARCS_PBES2).as_slice());
}
#[test]
fn const_matches_runtime_id_hmac_with_sm3() {
assert_eq!(
ID_HMAC_WITH_SM3,
runtime_encode(ARCS_ID_HMAC_WITH_SM3).as_slice()
);
}
#[test]
fn const_matches_runtime_sm4_cbc() {
assert_eq!(SM4_CBC, runtime_encode(ARCS_SM4_CBC).as_slice());
}
#[test]
fn id_pbkdf2_matches_published_bytes() {
assert_eq!(
ID_PBKDF2,
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C]
);
}
#[test]
fn id_ec_public_key_matches_published_bytes() {
assert_eq!(
ID_EC_PUBLIC_KEY,
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01]
);
}
#[test]
fn sm2p256v1_matches_published_bytes() {
assert_eq!(SM2P256V1, &[0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x82, 0x2D]);
}
#[test]
fn all_oids_round_trip_through_writer_reader() {
use crate::asn1::{reader, writer};
let oids: &[&[u8]] = &[
ID_EC_PUBLIC_KEY,
SM2P256V1,
SM2_SIGN_WITH_SM3,
ID_PBKDF2,
PBES2,
ID_HMAC_WITH_SM3,
SM4_CBC,
];
for oid in oids {
let mut buf = alloc::vec::Vec::new();
writer::write_oid(&mut buf, oid);
let (parsed, rest) = reader::read_oid(&buf).unwrap();
assert_eq!(parsed, *oid);
assert!(rest.is_empty());
}
}
}