Skip to content

ASN1 编码解码

ASN.1(Abstract Syntax Notation One)是一种用于描述和表示数据结构的标准格式。主要作用是为了跨平台、标准化数据表示和编码方式,使得不同系统可以正确理解和处理复杂的数据结构,尤其在安全和加密应用中非常常见。

SM2 中的 ASN1 编码解码

OpenSSL 对 SM2 加密结果进行了 ASN1 编码,解密时也要求密文编码格式为 ASN1 格式。GMObjC 提供了完整的 ASN1 编解码 API,支持密文格式转换。

objc
// 公钥
NSString *pubKey = @"0408E3FFF9505BCFAF9307E665E9229F4E1B3936437A870407EA3D97886BAFBC9"
                    "C624537215DE9507BC0E2DD276CF74695C99DF42424F28E9004CDE4678F63D698";
// 私钥
NSString *prikey = @"90F3A42B9FE24AB196305FD92EC82E647616C3A3694441FB3422E7838E24DEAE";

// 加密:明文 -> ASN1 格式密文(HEX 编码格式)
NSString *plaintext = @"123456";
NSString *asn1Hex = [GMSm2Utils encryptText:plaintext publicKey:pubKey];

// 解码:ASN1 -> C1C3C2 格式(HEX 编码格式)
NSString *c1c3c2Hex = [GMSm2Utils asn1DecodeToC1C3C2Hex:asn1Hex hasPrefix:NO];

// 编码:C1C3C2 -> ASN1 格式
NSString *asn1HexNew = [GMSm2Utils asn1EncodeWithC1C3C2Hex:c1c3c2Hex hasPrefix:NO];

密文顺序转换

GMObjC 支持 C1C3C2C1C2C3 两种密文格式的相互转换。密文通常不包含 04 标识开头,参数 hasPrefix 传入 NO 即可。

objc
// C1C3C2 转换为 C1C2C3(HEX 编码格式)
NSString *c1c2c3Hex = [GMSm2Utils convertC1C3C2HexToC1C2C3:c1c3c2Hex hasPrefix:NO];

// C1C2C3 转换为 C1C3C2 (HEX 编码格式)
NSString *c1c3c2Hex = [GMSm2Utils convertC1C2C3HexToC1C3C2:c1c2c3Hex hasPrefix:NO];

跨平台场景示例

当与其他平台对接时(如 Java 的 BouncyCastle),可能需要处理不同的密文格式。

objc
// 假设收到 Java 端的加密结果(C1C2C3 格式,带 04 前缀,HEX 编码格式)
NSString *c1c2c3Hex = @"04FCB4D9E7230B45C20D07F0...F52BD65AB31D4B15BDA1C65";

// 1. 转换为 C1C3C2 格式(保留 04 前缀,HEX 编码格式)
NSString *c1c3c2Hex = [GMSm2Utils convertC1C2C3HexToC1C3C2:c1c2c3Hex hasPrefix:YES];

// 2. 编码为 ASN1 格式(HEX 编码格式)
NSString *asn1Hex = [GMSm2Utils asn1EncodeWithC1C3C2Hex:c1c3c2Hex hasPrefix:YES];

// 3. 解密得到明文
NSString *plaintext = [GMSm2Utils decryptHex:asn1Hex privateKey:priKey];

知识补充

C1C3C2 含义

  • C1:椭圆曲线点,包含 x 和 y 坐标(x 和 y 分别是 32 字节,共 64 字节,Hex 格式则为 128 字节)
  • C3:消息认证码,即摘要值(SM3 摘要值 32 字节,HEX 编码格式则为 64 字节)
  • C2:加密数据,即明文加密后的数据(与原始数据长度相同)

密文格式标识

  • 02 或 03:压缩表示形式
  • 04:未压缩表示形式
  • 06 或 07:混合表示形式

hasPrefix 参数说明

在调用 ASN1 编解码和密文转换相关 API 时,需要注意 hasPrefix 参数:

  • 当密文带有 04 前缀时,设置为 YES
  • 当密文不带前缀时,设置为 NO
  • 可以通过观察密文或与其他平台确认是否带有前缀

基于 MIT 许可发布