URL中嵌套用戶名:密碼的問題處理(base64加密的方式)

在添加一個新功能時,發現需要URL中嵌套user name 和passwd時,發現通過普通的方式,獲取不到資源,常會被服務器拒絕掉,反饋403信息。

通過分析這個url,發現服務器端使用了一個很簡單的加密協議。分析發現,使用的是base64位加密,把user and passwd 通過base64加密成一串字符串,然後在request header 上添加上,然後再去請求。就可以獲取到資源了。


加密以及解密的code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char base64char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *http_base64_encode(unsigned char *bindata, char * base64, int binlength)
{
	int i, j;
	unsigned char current;

	for (i = 0, j = 0; i < binlength; i += 3)
	{
		current = (bindata[i] >> 2);
		current &= (unsigned char)0x3F;
		base64[j++] = base64char[(int)current];

		current = ((unsigned char)(bindata[i] << 4)) & ((unsigned char)0x30);
		if (i + 1 >= binlength)
		{
			base64[j++] = base64char[(int)current];
			base64[j++] = '=';
			base64[j++] = '=';
			break;
		}
		current |= ((unsigned char)(bindata[i + 1] >> 4)) & ((unsigned char)0x0F);
		base64[j++] = base64char[(int)current];

		current = ((unsigned char)(bindata[i + 1] << 2)) & ((unsigned char)0x3C);
		if (i + 2 >= binlength)
		{
			base64[j++] = base64char[(int)current];
			base64[j++] = '=';
			break;
		}
		current |= ((unsigned char)(bindata[i + 2] >> 6)) & ((unsigned char)0x03);
		base64[j++] = base64char[(int)current];

		current = ((unsigned char)bindata[i + 2]) & ((unsigned char)0x3F);
		base64[j++] = base64char[(int)current];
	}
	base64[j] = '\0';
	return base64;
}

int http_base64_decode(const char * base64, unsigned char * bindata)
{
	int i, j;
	unsigned char k;
	unsigned char temp[4];
	for (i = 0, j = 0; base64[i] != '\0'; i += 4)
	{
		memset(temp, 0xFF, sizeof(temp));
		for (k = 0; k < 64; k++)
		{
			if (base64char[k] == base64[i])
				temp[0] = k;
		}
		for (k = 0; k < 64; k++)
		{
			if (base64char[k] == base64[i + 1])
				temp[1] = k;
		}
		for (k = 0; k < 64; k++)
		{
			if (base64char[k] == base64[i + 2])
				temp[2] = k;
		}
		for (k = 0; k < 64; k++)
		{
			if (base64char[k] == base64[i + 3])
				temp[3] = k;
		}
		bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] << 2)) & 0xFC)) | ((unsigned char)((unsigned char)(temp[1] >> 4) & 0x03));
		if (base64[i + 2] == '=')
			break;
		bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4)) & 0xF0)) | ((unsigned char)((unsigned char)(temp[2] >> 2) & 0x0F));
		if (base64[i + 3] == '=')
			break;
		bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6)) & 0xF0)) | ((unsigned char)(temp[3] & 0x3F));
	}
	return j;
}



然後請求的header:

			snprintf(pcRequest, iRequestBuffSize, "GET /%s HTTP/1.1\r\n"
					"Authorization: Basic %s\r\n"
					"User-Agent: curl/7.35.0\r\n"
					"Host: %s\r\nConnection: keep-alive\r\n"
					"Accept: */*\r\n\r\n",
					pcFile, acEncodeBuff, acHost);

就可以獲取到資源了.


改進版本:

偶然的機會,閱讀了一個libghttp源碼(有侷限性,只支持http,適合入門學習),發現上面也使用了bash64的encode,發現它那個寫的比上面的好很多,相對上者,比較清晰明瞭簡介,雖然實現的效果是一樣的,但是更傾向於下着,所以,分享一下,後期遇到這種問題可以直接拿來使用。


const char b64_alphabet[65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		"abcdefghijklmnopqrstuvwxyz"
		"0123456789+/="};

char *http_base64_encode(const char *text)
{
	/* The tricky thing about this is doing the padding at the end,
	 * doing the bit manipulation requires a bit of concentration only */
	char *buffer = NULL;
	char *point = NULL;
	int inlen = 0;
	int outlen = 0;

	/* check our args */
	if (text == NULL)
		return NULL;

	/* Use 'buffer' to store the output. Work out how big it should be...
	 * This must be a multiple of 4 bytes */

	inlen = strlen(text);
	/* check our arg...avoid a pesky FPE */
	if (inlen == 0)
	{
		buffer = malloc(sizeof(char));
		buffer[0] = '\0';
		return buffer;
	}
	outlen = (inlen * 4) / 3;
	if ((inlen % 3) > 0) /* got to pad */
		outlen += 4 - (inlen % 3);

	buffer = malloc(outlen + 1); /* +1 for the \0 */
	memset(buffer, 0, outlen + 1); /* initialize to zero */

	/* now do the main stage of conversion, 3 bytes at a time,
	 * leave the trailing bytes (if there are any) for later */

	for (point = buffer; inlen >= 3; inlen -= 3, text += 3)
	{
		*(point++) = b64_alphabet[*text >> 2];
		*(point++) = b64_alphabet[(*text << 4 & 0x30) | *(text + 1) >> 4];
		*(point++) = b64_alphabet[(*(text + 1) << 2 & 0x3c) | *(text + 2) >> 6];
		*(point++) = b64_alphabet[*(text + 2) & 0x3f];
	}

	/* Now deal with the trailing bytes */
	if (inlen)
	{
		/* We always have one trailing byte */
		*(point++) = b64_alphabet[*text >> 2];
		*(point++) = b64_alphabet[(*text << 4 & 0x30) | (inlen == 2 ? *(text + 1) >> 4 : 0)];
		*(point++) = (inlen == 1 ? '=' : b64_alphabet[*(text + 1) << 2 & 0x3c]);
		*(point++) = '=';
	}

	*point = '\0';

	return buffer;
}


分析wget源碼時,看到base64的另一種加密方式,可以參考選擇哪個方式

/* Encode the octets in DATA of length LENGTH to base64 format,
 storing the result to DEST.  The output will be zero-terminated,
 and must point to a writable buffer of at least
 1+BASE64_LENGTH(length) bytes.  The function returns the length of
 the resulting base64 data, not counting the terminating zero.

 This implementation does not emit newlines after 76 characters of
 base64 data.  */

int base64_encode(const void *data, int length, char *dest)
{
	/* Conversion table.  */
	static const char tbl[64] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
	    'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
	    'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
	/* Access bytes in DATA as unsigned char, otherwise the shifts below
	 don't work for data with MSB set. */
	const unsigned char *s = data;
	/* Theoretical ANSI violation when length < 3. */
	const unsigned char *end = (const unsigned char *)data + length - 2;
	char *p = dest;

	/* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
	for (; s < end; s += 3)
	{
		*p++ = tbl[s[0] >> 2];
		*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
		*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
		*p++ = tbl[s[2] & 0x3f];
	}

	/* Pad the result if necessary...  */
	switch (length % 3)
	{
		case 1:
			*p++ = tbl[s[0] >> 2];
			*p++ = tbl[(s[0] & 3) << 4];
			*p++ = '=';
			*p++ = '=';
			break;
		case 2:
			*p++ = tbl[s[0] >> 2];
			*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
			*p++ = tbl[((s[1] & 0xf) << 2)];
			*p++ = '=';
			break;
	}
	/* ...and zero-terminate it.  */
	*p = '\0';

	return p - dest;
}

/* Store in C the next non-whitespace character from the string, or \0
 when end of string is reached.  */
#define NEXT_CHAR(c, p) do {                    \
  c = (unsigned char) *p++;                     \
} while (ISSPACE (c))

#define IS_ASCII(c) (((c) & 0x80) == 0)

/* Decode data from BASE64 (a null-terminated string) into memory
 pointed to by DEST.  DEST is assumed to be large enough to
 accomodate the decoded data, which is guaranteed to be no more than
 3/4*strlen(base64).

 Since DEST is assumed to contain binary data, it is not
 NUL-terminated.  The function returns the length of the data
 written to TO.  -1 is returned in case of error caused by malformed
 base64 input.

 This function originates from Free Recode.  */

int base64_decode(const char *base64, void *dest)
{
	/* Table of base64 values for first 128 characters.  Note that this
	 assumes ASCII (but so does Wget in other places).  */
	static const signed char base64_char_to_value[128] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*   0-  9 */
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  10- 19 */
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  20- 29 */
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  30- 39 */
	-1, -1, -1, 62, -1, -1, -1, 63, 52, 53, /*  40- 49 */
	54, 55, 56, 57, 58, 59, 60, 61, -1, -1, /*  50- 59 */
	-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, /*  60- 69 */
	5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /*  70- 79 */
	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /*  80- 89 */
	25, -1, -1, -1, -1, -1, -1, 26, 27, 28, /*  90- 99 */
	29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */
	39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */
	49, 50, 51, -1, -1, -1, -1, -1 /* 120-127 */
	};
#define BASE64_CHAR_TO_VALUE(c) ((int) base64_char_to_value[c])
#define IS_BASE64(c) ((IS_ASCII (c) && BASE64_CHAR_TO_VALUE (c) >= 0) || c == '=')

	const char *p = base64;
	char *q = dest;

	while (1)
	{
		unsigned char c;
		unsigned long value;

		/* Process first byte of a quadruplet.  */
		NEXT_CHAR(c, p);
		if (!c)
			break;
		if (c == '=' || !IS_BASE64(c))
			return -1; /* illegal char while decoding base64 */
		value = BASE64_CHAR_TO_VALUE (c) << 18;

		/* Process second byte of a quadruplet.  */
		NEXT_CHAR(c, p);
		if (!c)
			return -1; /* premature EOF while decoding base64 */
		if (c == '=' || !IS_BASE64(c))
			return -1; /* illegal char while decoding base64 */
		value |= BASE64_CHAR_TO_VALUE (c) << 12;
		*q++ = value >> 16;

		/* Process third byte of a quadruplet.  */
		NEXT_CHAR(c, p);
		if (!c)
			return -1; /* premature EOF while decoding base64 */
		if (!IS_BASE64(c))
			return -1; /* illegal char while decoding base64 */

		if (c == '=')
		{
			NEXT_CHAR(c, p);
			if (!c)
				return -1; /* premature EOF while decoding base64 */
			if (c != '=')
				return -1; /* padding `=' expected but not found */
			continue;
		}

		value |= BASE64_CHAR_TO_VALUE (c) << 6;
		*q++ = 0xff & value >> 8;

		/* Process fourth byte of a quadruplet.  */
		NEXT_CHAR(c, p);
		if (!c)
			return -1; /* premature EOF while decoding base64 */
		if (c == '=')
			continue;
		if (!IS_BASE64(c))
			return -1; /* illegal char while decoding base64 */

		value |= BASE64_CHAR_TO_VALUE(c);
		*q++ = 0xff & value;
	}
#undef IS_BASE64
#undef BASE64_CHAR_TO_VALUE

	return q - (char *)dest;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章