162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/errno.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ciint ceph_armor(char *dst, const char *src, const char *end);
662306a36Sopenharmony_ciint ceph_unarmor(char *dst, const char *src, const char *end);
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * base64 encode/decode.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic const char *pem_key =
1362306a36Sopenharmony_ci	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic int encode_bits(int c)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	return pem_key[c];
1862306a36Sopenharmony_ci}
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int decode_bits(char c)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	if (c >= 'A' && c <= 'Z')
2362306a36Sopenharmony_ci		return c - 'A';
2462306a36Sopenharmony_ci	if (c >= 'a' && c <= 'z')
2562306a36Sopenharmony_ci		return c - 'a' + 26;
2662306a36Sopenharmony_ci	if (c >= '0' && c <= '9')
2762306a36Sopenharmony_ci		return c - '0' + 52;
2862306a36Sopenharmony_ci	if (c == '+')
2962306a36Sopenharmony_ci		return 62;
3062306a36Sopenharmony_ci	if (c == '/')
3162306a36Sopenharmony_ci		return 63;
3262306a36Sopenharmony_ci	if (c == '=')
3362306a36Sopenharmony_ci		return 0; /* just non-negative, please */
3462306a36Sopenharmony_ci	return -EINVAL;
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciint ceph_armor(char *dst, const char *src, const char *end)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	int olen = 0;
4062306a36Sopenharmony_ci	int line = 0;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	while (src < end) {
4362306a36Sopenharmony_ci		unsigned char a, b, c;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		a = *src++;
4662306a36Sopenharmony_ci		*dst++ = encode_bits(a >> 2);
4762306a36Sopenharmony_ci		if (src < end) {
4862306a36Sopenharmony_ci			b = *src++;
4962306a36Sopenharmony_ci			*dst++ = encode_bits(((a & 3) << 4) | (b >> 4));
5062306a36Sopenharmony_ci			if (src < end) {
5162306a36Sopenharmony_ci				c = *src++;
5262306a36Sopenharmony_ci				*dst++ = encode_bits(((b & 15) << 2) |
5362306a36Sopenharmony_ci						     (c >> 6));
5462306a36Sopenharmony_ci				*dst++ = encode_bits(c & 63);
5562306a36Sopenharmony_ci			} else {
5662306a36Sopenharmony_ci				*dst++ = encode_bits((b & 15) << 2);
5762306a36Sopenharmony_ci				*dst++ = '=';
5862306a36Sopenharmony_ci			}
5962306a36Sopenharmony_ci		} else {
6062306a36Sopenharmony_ci			*dst++ = encode_bits(((a & 3) << 4));
6162306a36Sopenharmony_ci			*dst++ = '=';
6262306a36Sopenharmony_ci			*dst++ = '=';
6362306a36Sopenharmony_ci		}
6462306a36Sopenharmony_ci		olen += 4;
6562306a36Sopenharmony_ci		line += 4;
6662306a36Sopenharmony_ci		if (line == 64) {
6762306a36Sopenharmony_ci			line = 0;
6862306a36Sopenharmony_ci			*(dst++) = '\n';
6962306a36Sopenharmony_ci			olen++;
7062306a36Sopenharmony_ci		}
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci	return olen;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciint ceph_unarmor(char *dst, const char *src, const char *end)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	int olen = 0;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	while (src < end) {
8062306a36Sopenharmony_ci		int a, b, c, d;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci		if (src[0] == '\n') {
8362306a36Sopenharmony_ci			src++;
8462306a36Sopenharmony_ci			continue;
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci		if (src + 4 > end)
8762306a36Sopenharmony_ci			return -EINVAL;
8862306a36Sopenharmony_ci		a = decode_bits(src[0]);
8962306a36Sopenharmony_ci		b = decode_bits(src[1]);
9062306a36Sopenharmony_ci		c = decode_bits(src[2]);
9162306a36Sopenharmony_ci		d = decode_bits(src[3]);
9262306a36Sopenharmony_ci		if (a < 0 || b < 0 || c < 0 || d < 0)
9362306a36Sopenharmony_ci			return -EINVAL;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci		*dst++ = (a << 2) | (b >> 4);
9662306a36Sopenharmony_ci		if (src[2] == '=')
9762306a36Sopenharmony_ci			return olen + 1;
9862306a36Sopenharmony_ci		*dst++ = ((b & 15) << 4) | (c >> 2);
9962306a36Sopenharmony_ci		if (src[3] == '=')
10062306a36Sopenharmony_ci			return olen + 2;
10162306a36Sopenharmony_ci		*dst++ = ((c & 3) << 6) | d;
10262306a36Sopenharmony_ci		olen += 3;
10362306a36Sopenharmony_ci		src += 4;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci	return olen;
10662306a36Sopenharmony_ci}
107