xref: /linux/net/ceph/armor.c (revision 8bc7c5e525584903ea83332e18a2118ed3b1985e)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/errno.h>
4 
5 int ceph_armor(char *dst, const char *src, const char *end);
6 int ceph_unarmor(char *dst, const char *src, const char *end);
7 
8 /*
9  * base64 encode/decode.
10  */
11 
12 static const char *pem_key =
13 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
14 
15 static int encode_bits(int c)
16 {
17 	return pem_key[c];
18 }
19 
20 static int decode_bits(char c)
21 {
22 	if (c >= 'A' && c <= 'Z')
23 		return c - 'A';
24 	if (c >= 'a' && c <= 'z')
25 		return c - 'a' + 26;
26 	if (c >= '0' && c <= '9')
27 		return c - '0' + 52;
28 	if (c == '+')
29 		return 62;
30 	if (c == '/')
31 		return 63;
32 	if (c == '=')
33 		return 0; /* just non-negative, please */
34 	return -EINVAL;
35 }
36 
37 int ceph_armor(char *dst, const char *src, const char *end)
38 {
39 	int olen = 0;
40 	int line = 0;
41 
42 	while (src < end) {
43 		unsigned char a, b, c;
44 
45 		a = *src++;
46 		*dst++ = encode_bits(a >> 2);
47 		if (src < end) {
48 			b = *src++;
49 			*dst++ = encode_bits(((a & 3) << 4) | (b >> 4));
50 			if (src < end) {
51 				c = *src++;
52 				*dst++ = encode_bits(((b & 15) << 2) |
53 						     (c >> 6));
54 				*dst++ = encode_bits(c & 63);
55 			} else {
56 				*dst++ = encode_bits((b & 15) << 2);
57 				*dst++ = '=';
58 			}
59 		} else {
60 			*dst++ = encode_bits(((a & 3) << 4));
61 			*dst++ = '=';
62 			*dst++ = '=';
63 		}
64 		olen += 4;
65 		line += 4;
66 		if (line == 64) {
67 			line = 0;
68 			*(dst++) = '\n';
69 			olen++;
70 		}
71 	}
72 	return olen;
73 }
74 
75 int ceph_unarmor(char *dst, const char *src, const char *end)
76 {
77 	int olen = 0;
78 
79 	while (src < end) {
80 		int a, b, c, d;
81 
82 		if (src[0] == '\n') {
83 			src++;
84 			continue;
85 		}
86 		if (src + 4 > end)
87 			return -EINVAL;
88 		a = decode_bits(src[0]);
89 		b = decode_bits(src[1]);
90 		c = decode_bits(src[2]);
91 		d = decode_bits(src[3]);
92 		if (a < 0 || b < 0 || c < 0 || d < 0)
93 			return -EINVAL;
94 
95 		*dst++ = (a << 2) | (b >> 4);
96 		if (src[2] == '=')
97 			return olen + 1;
98 		*dst++ = ((b & 15) << 4) | (c >> 2);
99 		if (src[3] == '=')
100 			return olen + 2;
101 		*dst++ = ((c & 3) << 6) | d;
102 		olen += 3;
103 		src += 4;
104 	}
105 	return olen;
106 }
107