如何用Rust将SEC1编码的ECDSA公钥序列化为ASN.1 DER格式
SEC1编码ECDSA公钥转ASN.1 DER的Rust实现(无OpenSSL)
我已经实现了该转换的Python版本,但不知道怎么编写对应的Rust版本,且Rust代码不能使用openssl包。查资料后确定可以用k256="0.13.1"和der="0.7.5"库替代。目前已知公钥为Vec<u8>类型,不清楚如何将SEC1编码的ECDSA公钥转换为ASN.1 DER编码。以下是我写的部分代码:
use der::{Encoder, Length}; use k256::elliptic_curve::sec1::{ToEncodedPoint, FromEncodedPoint}; use k256::{PublicKey, EncodedPoint}; use der::asn1::{BitString, ObjectIdentifier}; fn sec1_to_der(sec1_key: &[u8]) -> Result<Vec<u8>, der::Error> { // Load the SEC1-encoded ECDSA public key as the public key object let public_key = PublicKey::from_sec1_bytes(sec1_key).expect("error"); // Define the OID for secp256k1 (1.3.132.0.10) let secp256k1_oid: ObjectIdentifier = k256::pkcs8::ObjectIdentifier::new("1.3.132.0.10"); // TODO: How to serialize SEC1-encoded ECDSA to ASN.1 DER format here } fn main() { let der_encoded_public_key:Vec<u8> = vec![3, 89, 191, 147, 51, 6, 188, 19, 231, 106, 80, 5, 56, 106, 114, 19, 115, 17, 94, 22, 217, 162, 205, 241, 154, 223, 129, 72, 143, 27, 102, 251, 246];; let der_key = sec1_to_der(&der_encoded_public_key); match der_key { Ok(der_key) => { println!("{:?}", der_key); } Err(e) => { println!("{:?}", e); } } }
补充:预期转换后的DER编码字节数组为:
[48, 86, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 10, 3, 66, 0, 4, 89, 191, 147, 51, 6, 188, 19, 231, 106, 80, 5, 56, 106, 114, 19, 115, 17, 94, 22, 217, 162, 205, 241, 154, 223, 129, 72, 143, 27, 102, 251, 246, 250, 38, 107, 239, 240, 74, 233, 61, 164, 22, 115, 130, 240, 115, 219, 245, 176, 223, 219, 226, 248, 174, 2, 113, 126, 158, 15, 175, 50, 83, 25, 191]
完整实现代码
要完成转换,需要构造符合X.509标准的ASN.1 DER结构,它由算法标识符和公钥比特串两个核心部分组成。以下是补全后的可运行代码:
use der::{asn1::{BitString, ObjectIdentifier, Null}, Encoder, Sequence, Writer}; use k256::elliptic_curve::sec1::ToEncodedPoint; use k256::PublicKey; // 定义算法标识符的ASN.1序列结构 #[derive(Sequence)] struct AlgorithmIdentifier { oid: ObjectIdentifier, parameters: Null, } fn sec1_to_der(sec1_key: &[u8]) -> Result<Vec<u8>, der::Error> { // 从SEC1字节加载公钥,返回错误而不是panic let public_key = PublicKey::from_sec1_bytes(sec1_key)?; // 构造secp256k1的算法标识符 let alg_id = AlgorithmIdentifier { oid: k256::pkcs8::OID, // 直接使用k256库预定义的secp256k1 OID parameters: Null, }; // 获取公钥的未压缩SEC1编码点,转换为比特串 let encoded_point = public_key.to_encoded_point(false); let pub_key_bitstring = BitString::from_bytes(encoded_point.as_bytes())?; // 构造顶层ASN.1序列:包含算法标识符和公钥比特串 let mut buf = Vec::new(); let mut writer = der::Writer::new(&mut buf); writer.sequence(|seq| { seq.encode(&alg_id)?; seq.encode(&pub_key_bitstring) })?; Ok(buf) } fn main() { let sec1_key: Vec<u8> = vec![3, 89, 191, 147, 51, 6, 188, 19, 231, 106, 80, 5, 56, 106, 114, 19, 115, 17, 94, 22, 217, 162, 205, 241, 154, 223, 129, 72, 143, 27, 102, 251, 246]; match sec1_to_der(&sec1_key) { Ok(der_key) => { println!("{:?}", der_key); // 验证是否与预期结果一致 let expected = vec![48, 86, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 10, 3, 66, 0, 4, 89, 191, 147, 51, 6, 188, 19, 231, 106, 80, 5, 56, 106, 114, 19, 115, 17, 94, 22, 217, 162, 205, 241, 154, 223, 129, 72, 143, 27, 102, 251, 246, 250, 38, 107, 239, 240, 74, 233, 61, 164, 22, 115, 130, 240, 115, 219, 245, 176, 223, 219, 226, 248, 174, 2, 113, 126, 158, 15, 175, 50, 83, 25, 191]; assert_eq!(der_key, expected, "转换结果与预期不符"); println!("转换成功,结果符合预期"); } Err(e) => { eprintln!("转换失败: {:?}", e); } } }
关键步骤说明
- 算法标识符构造:ASN.1中的算法标识符是一个序列,包含椭圆曲线的OID和参数(secp256k1的参数固定为NULL),这里直接使用
k256::pkcs8::OID避免手动构造OID的错误。 - 公钥比特串转换:将公钥的未压缩SEC1编码点转换为ASN.1比特串,这是X.509公钥要求的格式。
- 顶层序列编码:使用der库的Writer将算法标识符和公钥比特串组合成一个顶层ASN.1序列,最终编码为DER字节数组。
- 错误处理:替换原代码中的
expect为?,符合Rust的错误处理最佳实践,避免程序panic。
内容的提问来源于stack exchange,提问作者hewm
相关产品推荐
相关产品推荐

