aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca/codegen/asn1/asn1.c
blob: 13bfa5c193b7799ac68b479b47f2a8f48df5dcac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include "asn1.h"

#include <stdlib.h>

uint8_t *asn1_der_encode(const bn_t *r, const bn_t *s, size_t *result_len) {
    uint8_t r_len = (uint8_t) bn_to_bin_size(r);
    uint8_t s_len = (uint8_t) bn_to_bin_size(s);

	// Pad with one zero byte in case most-significant bit of top byte is one.
    uint8_t r_length = r_len + (bn_get_bit(r, (r_len * 8) - 1) ? 1 : 0);
    uint8_t s_length = s_len + (bn_get_bit(s, (s_len * 8) - 1) ? 1 : 0);

    // R and S are < 128 bytes, so 1 byte tag + 1 byte len + len bytes value
    size_t seq_value_len = 2 + r_length + 2 + s_length;
    size_t whole_len = seq_value_len;

    // The SEQUENCE length might be >= 128, so more bytes of length
    size_t seq_len_len = 0;
    if (seq_value_len >= 128) {
        size_t s = seq_value_len;
        do {
            seq_len_len++;
        } while ((s = s >> 8));
    }
    // seq_len_len bytes for length and one for length of length
    whole_len += seq_len_len + 1;

    // 1 byte tag for SEQUENCE
    whole_len += 1;

    uint8_t *data = malloc(whole_len);
    *result_len = whole_len;
    size_t i = 0;
    data[i++] = 0x30; // SEQUENCE
    if (seq_value_len < 128) {
        data[i++] = (uint8_t) seq_value_len;
    } else {
        data[i++] = (uint8_t) (seq_len_len | (1 << 7));
        for (size_t j = 0; j < seq_len_len; ++j) {
            data[i++] = (uint8_t) (seq_value_len & (0xff << (8 * (seq_len_len - j - 1))));
        }
    }
    data[i++] = 0x02; //INTEGER
    data[i++] = r_length;
    if (bn_get_bit(r, (r_len * 8) - 1)) {
        data[i++] = 0;
    }
    bn_to_bin(r, data + i);
    i += r_len;
    data[i++] = 0x02; //INTEGER
    data[i++] = s_length;
    if (bn_get_bit(s, (s_len * 8) - 1)) {
        data[i++] = 0;
    }
    bn_to_bin(s, data + i);
    i += s_len;

    return data;
}

bool asn1_der_decode(const uint8_t *sig, size_t sig_len, bn_t *r, bn_t *s) {
    size_t i = 0;
    if (sig[i++] != 0x30) {//SEQUENCE
        return false;
    }
    size_t seq_value_len = 0;
    if (!(sig[i] & 0x80)) {
        seq_value_len = sig[i++];
    } else {
        size_t seq_len_len = sig[i++] & 0x7f;
        while (seq_len_len > 0) {
            seq_value_len |= (sig[i++] << (seq_len_len - 1));
            seq_len_len--;
        }
    }

    if (sig[i++] != 0x02) {//INTEGER
        return false;
    }
    size_t r_length = sig[i++];
    size_t r_offset = i;
    i += r_length;

    if (sig[i++] != 0x02) {//INTEGER
        return false;
    }
    size_t s_length = sig[i++];
    size_t s_offset = i;
    i += s_length;

    if (i != sig_len) {
        return false;
    }

    bn_from_bin(sig + r_offset, r_length, r);
	bn_from_bin(sig + s_offset, s_length, s);
    return true;
}