csomh / source-git / rpm

Forked from source-git/rpm 4 years ago
Clone
2ff057
/* base64 encoder/decoder based on public domain implementation
2ff057
 * by Chris Venter */
2ff057
2ff057
#include <arpa/inet.h>
2ff057
#include <stdlib.h>
2ff057
2ff057
#include <rpm/rpmbase64.h>
2ff057
2ff057
2ff057
static char base64_encode_value(char value_in)
2ff057
{
2ff057
	static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2ff057
	if (value_in > 63) return '=';
2ff057
	return encoding[(int)value_in];
2ff057
}
2ff057
2ff057
static char *base64_encode_block(const char *plaintext_in, int length_in, char *codechar)
2ff057
{
2ff057
	const char *plainchar = plaintext_in;
2ff057
	const char *const plaintextend = plaintext_in + length_in;
2ff057
	char result;
2ff057
	char fragment;
2ff057
	
2ff057
	while (1) {
2ff057
		if (plainchar == plaintextend) {
2ff057
			return codechar;
2ff057
		}
2ff057
		fragment = *plainchar++;
2ff057
		result = (fragment & 0x0fc) >> 2;
2ff057
		*codechar++ = base64_encode_value(result);
2ff057
		result = (fragment & 0x003) << 4;
2ff057
		if (plainchar == plaintextend)
2ff057
		{
2ff057
			*codechar++ = base64_encode_value(result);
2ff057
			*codechar++ = '=';
2ff057
			*codechar++ = '=';
2ff057
			return codechar;
2ff057
		}
2ff057
		fragment = *plainchar++;
2ff057
		result |= (fragment & 0x0f0) >> 4;
2ff057
		*codechar++ = base64_encode_value(result);
2ff057
		result = (fragment & 0x00f) << 2;
2ff057
		if (plainchar == plaintextend)
2ff057
		{
2ff057
			*codechar++ = base64_encode_value(result);
2ff057
			*codechar++ = '=';
2ff057
			return codechar;
2ff057
		}
2ff057
		fragment = *plainchar++;
2ff057
		result |= (fragment & 0x0c0) >> 6;
2ff057
		*codechar++ = base64_encode_value(result);
2ff057
		result  = (fragment & 0x03f) >> 0;
2ff057
		*codechar++ = base64_encode_value(result);
2ff057
	}
2ff057
	/* control should not reach here */
2ff057
	return codechar;
2ff057
}
2ff057
2ff057
#define BASE64_DEFAULT_LINE_LENGTH 64
2ff057
2ff057
char *rpmBase64Encode(const void *data, size_t len, int linelen)
2ff057
{
2ff057
	size_t encodedlen;
2ff057
	const char *dataptr = data;
2ff057
	char *output;
2ff057
	char *outptr;
2ff057
	
2ff057
	if (data == NULL)
2ff057
		return NULL;
2ff057
2ff057
	if (linelen < 0)
2ff057
		linelen = BASE64_DEFAULT_LINE_LENGTH;
2ff057
2ff057
	linelen /= 4;
2ff057
	encodedlen = ((len + 2) / 3) * 4;
2ff057
	if (linelen > 0) {
2ff057
		encodedlen += encodedlen/(linelen * 4) + 1;
2ff057
	}
2ff057
	++encodedlen; /* for zero termination */
2ff057
2ff057
	output = malloc(encodedlen);
2ff057
	if (output == NULL)
2ff057
		return NULL;
2ff057
		
2ff057
	outptr = output;	
2ff057
	while (len > 0) {
2ff057
		if (linelen > 0 && len > linelen * 3) {
2ff057
			outptr = base64_encode_block(dataptr, linelen * 3, outptr);
2ff057
			len -= linelen * 3;
2ff057
			dataptr += linelen * 3;
2ff057
		} else {
2ff057
			outptr = base64_encode_block(dataptr, len, outptr);
2ff057
			len = 0;
2ff057
		}
2ff057
		if (linelen > 0) {
2ff057
			*outptr++ = '\n';
2ff057
		}
2ff057
	}
2ff057
	*outptr = '\0';
2ff057
	return output;
2ff057
}
2ff057
2ff057
static int base64_decode_value(unsigned char value_in)
2ff057
{
2ff057
	static const int decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,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,-1,-1,-1,-1,-1,-1,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};
2ff057
	value_in -= 43;
2ff057
	if (value_in >= sizeof(decoding)/sizeof(int))
2ff057
		return -1;
2ff057
	return decoding[value_in];
2ff057
}
2ff057
2ff057
static size_t base64_decode_block(const char *code_in, const size_t length_in, char *plaintext_out)
2ff057
{
2ff057
	const char *codechar = code_in;
2ff057
	char *plainchar = plaintext_out;
2ff057
	int fragment;
2ff057
	
2ff057
	*plainchar = 0;
2ff057
	
2ff057
	while (1)
2ff057
	{
2ff057
		do {
2ff057
			if (codechar == code_in+length_in)
2ff057
			{
2ff057
				return plainchar - plaintext_out;
2ff057
			}
2ff057
			fragment = base64_decode_value(*codechar++);
2ff057
		} while (fragment < 0);
2ff057
		*plainchar    = (char)((fragment & 0x03f) << 2);
2ff057
2ff057
		do {
2ff057
			if (codechar == code_in+length_in)
2ff057
			{
2ff057
				return plainchar - plaintext_out;
2ff057
			}
2ff057
			fragment = base64_decode_value(*codechar++);
2ff057
		} while (fragment < 0);
2ff057
		*plainchar++ |= (char)((fragment & 0x030) >> 4);
2ff057
		*plainchar    = (char)((fragment & 0x00f) << 4);
2ff057
2ff057
		do {
2ff057
			if (codechar == code_in+length_in)
2ff057
			{
2ff057
				return plainchar - plaintext_out;
2ff057
			}
2ff057
			fragment = base64_decode_value(*codechar++);
2ff057
		} while (fragment < 0);
2ff057
		*plainchar++ |= (char)((fragment & 0x03c) >> 2);
2ff057
		*plainchar    = (char)((fragment & 0x003) << 6);
2ff057
2ff057
		do {
2ff057
			if (codechar == code_in+length_in)
2ff057
			{
2ff057
				return plainchar - plaintext_out;
2ff057
			}
2ff057
			fragment = base64_decode_value(*codechar++);
2ff057
		} while (fragment < 0);
2ff057
		*plainchar++   |= (char)(fragment & 0x03f);
2ff057
	}
2ff057
	/* control should not reach here */
2ff057
	return plainchar - plaintext_out;
2ff057
}
2ff057
2ff057
int rpmBase64Decode(const char *in, void **out, size_t *outlen)
2ff057
{
2ff057
	size_t outcnt = 0;
2ff057
	const char *inptr = in;
2ff057
2ff057
	*out = NULL;
2ff057
2ff057
	if (in == NULL) {
2ff057
		return 1;
2ff057
	}
2ff057
	
2ff057
	while (*inptr != '\0') {
2ff057
		/* assume all ASCII control chars as whitespace */
2ff057
		if (*inptr > 32) {
2ff057
			if (base64_decode_value(*inptr) != -1) {
2ff057
				++outcnt;
2ff057
			} else {
2ff057
				return 3;
2ff057
			}
2ff057
		}
2ff057
		++inptr;
2ff057
	}
2ff057
	
2ff057
	if (outcnt % 4 != 0)
2ff057
		return 2;
2ff057
	
2ff057
	outcnt = (outcnt / 4) * 3;
2ff057
	
2ff057
	*out = malloc(outcnt + 1); /* base64_decode_block can write one extra character */
2ff057
	
2ff057
	if (*out == NULL)
2ff057
		return 4;
2ff057
	
2ff057
	*outlen = base64_decode_block(in, inptr - in, *out);
2ff057
2ff057
	return 0;
2ff057
}
2ff057
2ff057
#define CRC24_INIT 0xb704ce
2ff057
#define CRC24_POLY 0x1864cfb
2ff057
2ff057
char *rpmBase64CRC(const unsigned char *data, size_t len)
2ff057
{
2ff057
	uint32_t crc = CRC24_INIT;
2ff057
	int i;
2ff057
2ff057
	while (len--) {
2ff057
		crc ^= (*data++) << 16;
2ff057
		for (i = 0; i < 8; i++) {
2ff057
			crc <<= 1;
2ff057
			if (crc & 0x1000000)
2ff057
				crc ^= CRC24_POLY;
2ff057
		}
2ff057
	}
2ff057
	crc = htonl(crc & 0xffffff);
2ff057
	data = (unsigned char *)&crc;
2ff057
	++data;
2ff057
	return rpmBase64Encode(data, 3, 0);
2ff057
}
2ff057
2ff057
#ifdef BASE64_TEST
2ff057
#include <stdio.h>
2ff057
#include <string.h>
2ff057
2ff057
int main(int argc, char *argv[]) 
2ff057
{
2ff057
	static char tst[]="wtrt8122čLýáj\x20s ~ýhž\t4\x02šjjmBvž^%$RTš#á.íěj\x1hčýčŤc+";
2ff057
	char *encoded;
2ff057
	void *decoded;
2ff057
	size_t size;
2ff057
	int err;
2ff057
	printf("Original: %lu\n%s\n", sizeof(tst)-1, tst);
2ff057
	encoded = rpmBase64Encode(tst, sizeof(tst)-1, 64);
2ff057
	printf("Encoded: %lu\n%s\n", strlen(encoded), encoded);
2ff057
	if ((err = rpmBase64Decode(encoded, &decoded, &size)) != 0) {
2ff057
		fprintf(stderr, "Error in decode: %d\n", err);
2ff057
		return 1;
2ff057
	}
2ff057
	printf("Decoded:\n%.*s\n", (int)size, (char *)decoded);
2ff057
	if (size != sizeof(tst)-1) {
2ff057
		fprintf(stderr, "Size differs orig: %lu new: %lu\n", sizeof(tst)-1, size);
2ff057
		return 1;
2ff057
	}
2ff057
	if (memcmp(tst, decoded, size) != 0) {
2ff057
		fprintf(stderr, "Decoded data differs.\n");
2ff057
		return 1;
2ff057
	}
2ff057
	fprintf(stderr, "OK\n");
2ff057
	return 0;
2ff057
}
2ff057
#endif
2ff057