ASN.1语法以及在python中如何编码解码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ASN.1语法以及在python中如何编码解码相关的知识,希望对你有一定的参考价值。

参考技术A

ASN.1的文章本来是免费的,但是有的人一定要搞小动作,咱惹不起就只能躲着了,做了一些修改后,改为付费文章



应用程序在网络协议的应用层对payload数据,多使用ASN.1标准进行处理

ASN.1

ASN.1



Abstract Syntax Notation One,抽象语法标记,ASN.1是描述数据格式的标准方法, 它不管语言是如何执行、这些数据具体指什么、用什么类型的编码规则 ,是一种抽象的语法



ASN.1由两部分组成:

一部分描述信息内数据,数据类型及序列格式

另一部分描述如何将各部分组成消息

语法

例如

Report ::= SEQUENCE

author OCTET STRING,

title OCTET STRING,

body OCTET STRING,

biblio Bibliography

 

Report是结构体名称

SEQUENCE表示消息是由许多数据单元构成的

中括号里面是各种类型的数据单元

前三个数据单元author/title/body的类型是OCTET STRING

最后一个数据单元biblio的类型是另一个ASN.1结构体

Bibliography ::= SEQUENCE

author OCTET STRING

title OCTET STRING

publisher OCTET STRING

year OCTET STRING

 

数据类型

类型含义

NULL空

BOOLEAN布尔类型

INTEGER整型

REAL实数类型

BIT STRING比特串

OCTEC STRING字节串

OBJECT IDENTIFIER实体标识符

ENUMERATED枚举类型

SEQUENCE序列

SEQUENCE OF类型的序列

SET集合

SET OF类型的集合

CHOICECHOICE类型

...STRING(有很多就不一一列举)字符串类型

UTCTime时间类型

GeneralizedTime时间类型

ASN.1文件结构

例如

Foo DEFINITIONS ::= BEGIN

    Question ::= SEQUENCE

        id        INTEGER,

        question  IA5String

   

    Answer ::= SEQUENCE

        id        INTEGER,

        answer    BOOLEAN

   

END 

解析上面的ASN.1文件的结构

ASN.1支持的编码规则

基本编码规则(BER)

规范编码规则(CER)

识别名编码规则(DER)

压缩编码规则(PER)

XML编码规则(XER)

python如何对ASN.1结构的信息编码和解码

如果我们想用python对信息进行编码,需要明确几点:

提供的ASN.1格式的数据

更多内容,请参考公-中-号, 汽车网络诊断通信

asn1 编码与解码

asn1c

本文使用的是asn1c工具,可在github-asn1c下载。

编码

首先定义asn1结构,文件命名为en.asn1

RectangleTest DEFINITIONS ::=
BEGIN
 
Rectangle ::= SEQUENCE {
    height  INTEGER,        -- Height of the rectangle
    width   INTEGER         -- Width of the rectangle
}
 
END

执行命令生成编码解码所需的.h和.c文件。

asn1c -fnative-types en.asn1
  • -fnative-types:尽可能使用本机的数据类型(int,double),而不要使用复合INTEGER_t,ENUMERATED_t和REAL_t类型。(当然不加也没什么影响)

然后编写编码主函数main.c文件

#include <stdio.h>
#include <sys/types.h>
#include <Rectangle.h>   /* Rectangle ASN.1 type  */
 
/*
 * This is a custom function which writes the
 * encoded output into some FILE stream.
 */
static int
write_out(const void *buffer, size_t size, void *app_key) {
    FILE *out_fp = app_key;
    size_t wrote;
 
    wrote = fwrite(buffer, 1, size, out_fp);
 
    return (wrote == size) ? 0 : -1;
}
 
int main(int ac, char **av) {
    Rectangle_t *rectangle; /* Type to encode        */
    asn_enc_rval_t ec;      /* Encoder return value  */
 
    /* Allocate the Rectangle_t */
    rectangle = calloc(1, sizeof(Rectangle_t)); /* not malloc! */
    if(!rectangle) {
      perror("calloc() failed");
      exit(71); /* better, EX_OSERR */
    }
 
    /* Initialize the Rectangle members */
    rectangle->height = 42;  /* any random value */
    rectangle->width  = 23;  /* any random value */
     
    /* BER encode the data if filename is given */
    if(ac < 2) {
      fprintf(stderr, "Specify filename for BER output
");
    } else {
      const char *filename = av[1];
      FILE *fp = fopen(filename, "wb");   /* for BER output */
 
      if(!fp) {
        perror(filename);
        exit(71); /* better, EX_OSERR */
      }
  
      /* Encode the Rectangle type as BER (DER) */
      ec = der_encode(&asn_DEF_Rectangle,
            rectangle, write_out, fp);
      fclose(fp);
      if(ec.encoded == -1) {
        fprintf(stderr,
          "Could not encode Rectangle (at %s)
",
          ec.failed_type ? ec.failed_type->name : "unknown");
        exit(65); /* better, EX_DATAERR */
      } else {
        fprintf(stderr, "Created %s with BER encoded Rectangle
",
          filename);
      }
    }
 
    /* Also print the constructed Rectangle XER encoded (XML) */
    xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
 
    return 0; /* Encoding finished successfully */
}

删除converter-example.c文件(这个文件是main函数样例,我们已经自己定义了main函数,如果不删除gcc会报main重复定义错误)。

rm converter-example.c

编译文件

cc -I. -o rdecode *.c
  • -I.:指定当前目录为头文件夹。

这里可能会未定义报措,这个是asn1c的bug
技术图片

我们只要到 /usr/local/share/asn1c/把对应的C文件复制过来就行。

cp /usr/local/share/asn1c/BIT_STRING_oer.c ./
cp /usr/local/share/asn1c/OCTET_STRING_oer.c ./

运行命令生成asn1二进制文件。

./rencode a.asn1

技术图片

可以看到已经生成了高值为42,宽值为23的asn1二进制文件。

解码

与编码步骤类似,重复部分不再叙述。
编写解码主函数main.c文件

#include <stdio.h>
#include <sys/types.h>
#include <Rectangle.h>   /* Rectangle ASN.1 type  */
 
int main(int ac, char **av) {
    char buf[1024];      /* Temporary buffer      */
    Rectangle_t *rectangle = 0; /* Type to decode */
    asn_dec_rval_t rval; /* Decoder return value  */
    FILE *fp;            /* Input file handler    */
    size_t size;         /* Number of bytes read  */
    char *filename;      /* Input file name */
 
    /* Require a single filename argument */
    if(ac != 2) {
      fprintf(stderr, "Usage: %s <file.ber>
", av[0]);
      exit(64); /* better, EX_USAGE */
    } else {
      filename = av[1];
    }
 
    /* Open input file as read-only binary */
    fp = fopen(filename, "rb");
    if(!fp) {
      perror(filename);
      exit(66); /* better, EX_NOINPUT */
    }
  
    /* Read up to the buffer size */
    size = fread(buf, 1, sizeof(buf), fp);
    fclose(fp);
    if(!size) {
      fprintf(stderr, "%s: Empty or broken
", filename);
      exit(65); /* better, EX_DATAERR */
    }
 
    /* Decode the input buffer as Rectangle type */
    rval = ber_decode(0, &asn_DEF_Rectangle,
      (void **)&rectangle, buf, size);
    if(rval.code != RC_OK) {
      fprintf(stderr,
        "%s: Broken Rectangle encoding at byte %ld
",
        filename, (long)rval.consumed);
      exit(65); /* better, EX_DATAERR */
    }
 
    /* Print the decoded Rectangle type as XML */
    xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
 
    return 0; /* Decoding finished successfully */
}

执行命令编译文件

cc -I. -o rdecode *.c

成功解码
技术图片

参考

github asn1c

以上是关于ASN.1语法以及在python中如何编码解码的主要内容,如果未能解决你的问题,请参考以下文章

ASN.1编解码:asn1c的基本使用

ASN.1笔记——标准编码规则BER

ASN.1解码

ASN.1编解码:asn1c的版本分析-诺基亚

ASN.1编解码:ORAN-E2AP分析

ASN.1编解码:asn1c-ORAN-E2AP