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\n");
    } 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)\n",
          ec.failed_type ? ec.failed_type->name : "unknown");
        exit(65); /* better, EX_DATAERR */
      } else {
        fprintf(stderr, "Created %s with BER encoded Rectangle\n",
          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>\n", 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\n", 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\n",
        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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM