18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/errno.h>
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ciint ceph_armor(char *dst, const char *src, const char *end);
68c2ecf20Sopenharmony_ciint ceph_unarmor(char *dst, const char *src, const char *end);
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci * base64 encode/decode.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic const char *pem_key =
138c2ecf20Sopenharmony_ci	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic int encode_bits(int c)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	return pem_key[c];
188c2ecf20Sopenharmony_ci}
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int decode_bits(char c)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	if (c >= 'A' && c <= 'Z')
238c2ecf20Sopenharmony_ci		return c - 'A';
248c2ecf20Sopenharmony_ci	if (c >= 'a' && c <= 'z')
258c2ecf20Sopenharmony_ci		return c - 'a' + 26;
268c2ecf20Sopenharmony_ci	if (c >= '0' && c <= '9')
278c2ecf20Sopenharmony_ci		return c - '0' + 52;
288c2ecf20Sopenharmony_ci	if (c == '+')
298c2ecf20Sopenharmony_ci		return 62;
308c2ecf20Sopenharmony_ci	if (c == '/')
318c2ecf20Sopenharmony_ci		return 63;
328c2ecf20Sopenharmony_ci	if (c == '=')
338c2ecf20Sopenharmony_ci		return 0; /* just non-negative, please */
348c2ecf20Sopenharmony_ci	return -EINVAL;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ciint ceph_armor(char *dst, const char *src, const char *end)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	int olen = 0;
408c2ecf20Sopenharmony_ci	int line = 0;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	while (src < end) {
438c2ecf20Sopenharmony_ci		unsigned char a, b, c;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci		a = *src++;
468c2ecf20Sopenharmony_ci		*dst++ = encode_bits(a >> 2);
478c2ecf20Sopenharmony_ci		if (src < end) {
488c2ecf20Sopenharmony_ci			b = *src++;
498c2ecf20Sopenharmony_ci			*dst++ = encode_bits(((a & 3) << 4) | (b >> 4));
508c2ecf20Sopenharmony_ci			if (src < end) {
518c2ecf20Sopenharmony_ci				c = *src++;
528c2ecf20Sopenharmony_ci				*dst++ = encode_bits(((b & 15) << 2) |
538c2ecf20Sopenharmony_ci						     (c >> 6));
548c2ecf20Sopenharmony_ci				*dst++ = encode_bits(c & 63);
558c2ecf20Sopenharmony_ci			} else {
568c2ecf20Sopenharmony_ci				*dst++ = encode_bits((b & 15) << 2);
578c2ecf20Sopenharmony_ci				*dst++ = '=';
588c2ecf20Sopenharmony_ci			}
598c2ecf20Sopenharmony_ci		} else {
608c2ecf20Sopenharmony_ci			*dst++ = encode_bits(((a & 3) << 4));
618c2ecf20Sopenharmony_ci			*dst++ = '=';
628c2ecf20Sopenharmony_ci			*dst++ = '=';
638c2ecf20Sopenharmony_ci		}
648c2ecf20Sopenharmony_ci		olen += 4;
658c2ecf20Sopenharmony_ci		line += 4;
668c2ecf20Sopenharmony_ci		if (line == 64) {
678c2ecf20Sopenharmony_ci			line = 0;
688c2ecf20Sopenharmony_ci			*(dst++) = '\n';
698c2ecf20Sopenharmony_ci			olen++;
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci	return olen;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint ceph_unarmor(char *dst, const char *src, const char *end)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	int olen = 0;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	while (src < end) {
808c2ecf20Sopenharmony_ci		int a, b, c, d;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		if (src[0] == '\n') {
838c2ecf20Sopenharmony_ci			src++;
848c2ecf20Sopenharmony_ci			continue;
858c2ecf20Sopenharmony_ci		}
868c2ecf20Sopenharmony_ci		if (src + 4 > end)
878c2ecf20Sopenharmony_ci			return -EINVAL;
888c2ecf20Sopenharmony_ci		a = decode_bits(src[0]);
898c2ecf20Sopenharmony_ci		b = decode_bits(src[1]);
908c2ecf20Sopenharmony_ci		c = decode_bits(src[2]);
918c2ecf20Sopenharmony_ci		d = decode_bits(src[3]);
928c2ecf20Sopenharmony_ci		if (a < 0 || b < 0 || c < 0 || d < 0)
938c2ecf20Sopenharmony_ci			return -EINVAL;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		*dst++ = (a << 2) | (b >> 4);
968c2ecf20Sopenharmony_ci		if (src[2] == '=')
978c2ecf20Sopenharmony_ci			return olen + 1;
988c2ecf20Sopenharmony_ci		*dst++ = ((b & 15) << 4) | (c >> 2);
998c2ecf20Sopenharmony_ci		if (src[3] == '=')
1008c2ecf20Sopenharmony_ci			return olen + 2;
1018c2ecf20Sopenharmony_ci		*dst++ = ((c & 3) << 6) | d;
1028c2ecf20Sopenharmony_ci		olen += 3;
1038c2ecf20Sopenharmony_ci		src += 4;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci	return olen;
1068c2ecf20Sopenharmony_ci}
107