繁体   English   中英

ASN.1 长度编码(使用 BER)

[英]ASN.1 Length encoding (using BER)

这应该是非常基本的,但是,我已经摸索了一段时间,所以我想我应该四处问问,所以在此先感谢您的帮助。

所以我的问题是,我有这个序列:

User::=SEQUENCE {
userid [0] IA5String,
password [1] Implicit IA5String}

我想使用 BER 对以下内容进行编码,具有以下值:

{userid = "user", password = "pass"}

所以我们有 3 个“字段”TLV:

Tag is: 001 10000

我的问题是本身的长度,这应该是08 (我认为04从“用户”字节加上04字节的“通行证”)。

但在我的解决方案中:

L -> 0 0 0 0 1 1 1 0 (=14)  0E

我似乎无法找出原因。

在 BER 和 DER 编码规则中,每个数据元素都被编码为一个 Tag-Length-Value 序列。

在谈论非构造类型(例如 INTEGER 或 IA5String)时,值是按照该类型的规则编码的实际值。

当谈到构造类型(例如 SEQUENCE 或 SET)时,值是构造类型中包含的不同字段的 BER/DER 编码值。

考虑到这一点,我们可以接受您的类型

User::=SEQUENCE {
    userid [0] IA5String,
    password [1] IMPLICIT IA5String}

和您的数据价值

{userid = "user", password = "pass"}

我们可以开始编码了。

首先是 SEQUENCE 的标签,即 0x30,然后是长度,我们还不知道。 现在我们应该对构造的 SEQUENCE 的值进行编码。 所以我们开始对不同的字段进行编码。

我们需要对userid字段进行编码。 这是一个标记类型,在这里,取决于全局EXPLICITIMPLICIT选项,这可以构造或不构造: - 如果 EXPLICIT,我们将有标记 0xA0(用于构造上下文 0)、长度和标记类型:IA5String 是标签 0x16(通用 22),长度 0x04 和值 0x75 73 65 72 - 如果是 IMPLICIT,我们将有标签 0x80(对于非构造上下文 0),长度 0x04 和值 75 73 65 72

最后,我们需要对密码进行编码,在这种情况下我们没有疑问,添加了 IMPLICIT 关键字来强制隐式标记。 所以我们将有标签 0x81(对于非构造上下文 1),长度 0x04 和值 70 61 73 73

所以总而言之,我们有(假设全局 IMPLICIT)

30 0c
   80 04 75 73 65 72
   81 04 70 61 73 73

总共 14 个字节

或者如果全局显式

30 0e
   A0 06
      16 04 75 73 65 72
   81 04 70 61 73 73

总共 16 个字节

userid有效载荷为 4 个字节,加上有效载荷长度 (4) 和标记 (IA5String) 的 1 个字节。 这会产生 6 个字节的 TLV。 password值为 4 个字节,外加 1 个字节的有效载荷长度 (4) 和标记 (IA5String)。 SEQUENCE 的负载大小为 12 字节。 添加长度字节 (12) 和标记 (SEQUENCE),您将获得 14 个字节的结构。

Microsoft 网站上的更多信息: DER Transfer Syntax , Encoded Length and Value Bytes

请注意,序列的元素被标记,第一个显式(意味着在完整 IA5String 编码之前的“额外”标记/长度),第二个隐式(意味着替换原始 IA5String 标记/长度的标记/长度)。

因此,完整的编码将是 300ea006160475736572810470617373:

30 CONSTRUCTED SEQUENCE
0e Length 14
a0 CONSTRUCTED TAGGED 0
06 Length 6
16 IA5String
04 Length 4
75 'u'
73 's'
65 'e'
72 'r'
81 TAGGED 1
04 Length 4
70 'p'
61 'a'
73 's'
73 's'

请注意,默认情况下,ASN.1 模块定义可以声明隐式标签,但我假设情况并非如此,因为您提到的现有解决方案也为 SEQUENCE 标签提供了长度 14。

package binaryhex;

public class BinaryHex {

    public static void main(String[] args) {
        String s = "A8 59 A0 47 A0 15 80 01 01 81 02 01 F4 82 01 01 83 09 31 32 37 2E 30 2E 30 2E 31 81 07 32 33 30 5F 32 32 37 82 0E 32 30 31 36 30 38 32 32 31 34 35 36 31 30 83 01 00 84 01 00 A5 0F 80 03 44 53 4D 81 08 31 32 33 34 35 36 37 38 81 0E 32 30 31 36 30 38 32 32 31 34 35 36 31 30";
        String hexDumpStrWithoutSpace = s.replaceAll("\\s+", "");
        int length = calculateLength(hexDumpStrWithoutSpace);
        System.out.println("LENGTH: " + length);
    }

    private static int calculateLength(String hexDumpStrWithoutSpace) {
        int decimalValue = 0;
        boolean tag = false;
        int i = 0;
        while (!tag) {
            String typeSub = hexDumpStrWithoutSpace.substring(i, i + 2);
            StringBuilder typeBinSB = new StringBuilder();
            for (int j = 0; j < typeSub.length(); j++) {
                typeBinSB.append(hexToBinary("" + typeSub.charAt(j)));
            }
            String typeBin = typeBinSB.toString();
            if (typeBin.charAt(2) == '0') {
                int tagInt = Integer.parseInt(typeBin.substring(3), 2);
                System.out.println("TAG: " + tagInt);
                tag = true;
            } else {
                String tagStr = typeBin.substring(3 - i / 2);
                if (tagStr.equals("11111")) {
                    i = i + 2;
                    continue;
                } else {
                    int tagInt = Integer.parseInt(tagStr, 2);
                    System.out.println("TAG: " + tagInt);
                    tag = true;
                    i = i + 2;
                }

            }
        }

        for (; i < hexDumpStrWithoutSpace.length();) {
            String lengthSub = hexDumpStrWithoutSpace.substring(i, i + 2);

            StringBuilder lengthBinSB = new StringBuilder();
            for (int j = 0; j < lengthSub.length(); j++) {
                lengthBinSB.append(hexToBinary("" + lengthSub.charAt(j)));
            }
            String lengthBin = lengthBinSB.toString();
            if (lengthBin.charAt(0) == '0') {
                Integer lengthInt = Integer.parseInt(lengthBin, 2);
                decimalValue = lengthInt + i;
                break;
            } else {
                Integer lengthOctets = Integer.parseInt(lengthBin.substring(1), 2);
                StringBuilder toBinSB = new StringBuilder();

                for (int k = 0; k < lengthOctets; k++) {
                    i = i + 2;
                    String toBin = hexDumpStrWithoutSpace.substring(i, i + 2);
                    for (int j = 0; j < toBin.length(); j++) {
                        toBinSB.append(hexToBinary("" + toBin.charAt(j)));
                    }
                }
                String lengthResult = toBinSB.toString();
                Integer lengthValue = Integer.parseInt(lengthResult, 2);
                decimalValue = lengthValue + i - 2;
                break;
            }
        }

        return decimalValue;
    }

    static String hexToBinary(String hex) {
        int i = Integer.parseInt(hex, 16);
        String bin = Integer.toBinaryString(i);
        if (bin.length() < 4) {
            while (bin.length() < 4) {
                bin = "0" + bin;
            }
        }
        return bin;
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM