v2 / vlib / crypto / pem / encode.v
59 lines · 49 sloc · 1.62 KB · 757929392e0e7a75fc1272116460981e589737d5
Raw
1module pem
2
3import encoding.base64
4import arrays
5
6// encode encodes the given block into a
7// string using the EncodeConfig. It returns an error if `block_type` is undefined
8// or if a value in `headers` contains an invalid character ':'
9//
10// default EncodeConfig values wrap lines at 64 bytes and use '\n' for newlines
11pub fn (block Block) encode(config EncodeConfig) !string {
12 if block.block_type == '' {
13 return error('crypto.pem: `encode` called with undefined `block_type`')
14 }
15 if block.headers.keys().any(it.contains(':')) || block.headers.values().any(it.contains(':')) {
16 return error('crypto.pem: invalid header character `:`')
17 }
18
19 // to avoid repeated struct access
20 newline := config.line_ending
21 length := config.line_length
22
23 mut inner := ''
24 if block.headers.len > 0 {
25 // Proc-Type must be written first if it is present
26 if block.headers['Proc-Type'].len > 0 {
27 inner += 'Proc-Type: 4,${block.headers['Proc-Type'][0].trim_string_left('4,')}' +
28 newline
29 }
30
31 for key, value in block.headers {
32 if key == 'Proc-Type' {
33 continue
34 }
35
36 for _, subvalue in value {
37 inner += '${key}: '
38 if key.len + subvalue.len < length {
39 inner += subvalue
40 } else {
41 inner += newline + wrap_lines(subvalue, newline, length)
42 }
43 inner += newline
44 }
45 }
46
47 inner += newline
48 }
49
50 inner += wrap_lines(base64.encode(block.data), newline, length)
51
52 return '${pem_begin}${block.block_type}${pem_eol}${newline}' + '${inner}' +
53 '${pem_end}${block.block_type}${pem_eol}'
54}
55
56@[inline]
57fn wrap_lines(str string, newline string, length int) string {
58 return arrays.chunk(str.bytes(), length).map(it.bytestr()).join(newline)
59}
60