diff options
Diffstat (limited to 'libpiano')
| -rw-r--r-- | libpiano/src/crypt.c | 311 | 
1 files changed, 120 insertions, 191 deletions
| diff --git a/libpiano/src/crypt.c b/libpiano/src/crypt.c index 0cc359e..d898205 100644 --- a/libpiano/src/crypt.c +++ b/libpiano/src/crypt.c @@ -24,226 +24,155 @@ THE SOFTWARE.  #include <string.h>  #include <stdio.h>  #include <stdlib.h> +#include <stdint.h>  #include "crypt_key_output.h"  #include "crypt_key_input.h"  #include "main.h" -#define byteswap32(x) (((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) | \ -		((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000)) +#define byteswap32(x) ((((x) >> 24) & 0x000000ff) | \ +		(((x) >> 8) & 0x0000ff00) | \ +		(((x) << 8) & 0x00ff0000) | \ +		(((x) << 24) & 0xff000000)) -/*	hex string to array of unsigned int values - *	@param hex string - *	@param return array - *	@param return size of array - *	@return nothing, yet - */ -void PianoHexToInts (const char *strHex, unsigned int **retInts, -		size_t *retIntsN) { -	size_t i, strHexN = strlen (strHex); -	unsigned int *arrInts = calloc (strHexN / 8, sizeof (*arrInts)); - -	/* unsigned int = 4 bytes, 8 chars in hex */ -	for (i = 0; i < strHexN; i++) { -		arrInts[i/8] |= ((strHex[i] < 'a' ? strHex[i]: strHex[i] + 9) & -				0x0f) << (7*4 - i*4); -	} -	*retInts = arrInts; -	*retIntsN = strHexN / 8; -} - -/*	decipher int array; reverse engineered from pandora source - *	@param decrypt-me - *	@param decrypt-me-length - *	@param return plain ints array - */ -void PianoDecipherInts (const unsigned int *cipherInts, size_t cipherIntsN, -		unsigned int **retPlainInts) { -	unsigned int *plainInts = calloc (cipherIntsN, sizeof (*plainInts)); -	size_t i, j; -	unsigned int f, l, r, lrExchange; - -	for (i = 0; i < cipherIntsN; i += 2) { -		l = cipherInts [i]; -		r = cipherInts [i+1]; - -		for (j = in_key_n + 1; j > 1; --j) { -			l ^= in_key_p [j]; -			 -			f = in_key_s [0][(l >> 24) & 0xff] + -					in_key_s [1][(l >> 16) & 0xff]; -			f ^= in_key_s [2][(l >> 8) & 0xff]; -			f += in_key_s [3][l & 0xff]; -			r ^= f; -			/* exchange l & r */ -			lrExchange = l; -			l = r; -			r = lrExchange; -		} -		/* exchange l & r */ -		lrExchange = l; -		l = r; -		r = lrExchange; -		r ^= in_key_p [1]; -		l ^= in_key_p [0]; -		plainInts [i] = l; -		plainInts [i+1] = r; -	} -	*retPlainInts = plainInts; -} - -/*	int array to string - *	@param int array - *	@param length of array - *	@return the string - */ -char *PianoIntsToString (const unsigned int *arrInts, size_t arrIntsN) { -	char *strDecoded = calloc (arrIntsN * 4 + 1, sizeof (*strDecoded)); -	size_t i; -	unsigned int *tmp; - -	for (i = 0; i < arrIntsN; i++) { -		/* map string to 4-byte int */ -		tmp = (unsigned int *) &strDecoded[i*4]; -		/* FIXME: big endian does not need byteswap? */ -		*tmp = byteswap32 (arrInts[i]); -	} -	return strDecoded; -} - -/*	decrypt hex-encoded string +/*	decrypt hex-encoded, blowfish-crypted string: decode 2 hex-encoded blocks, + *	decrypt, byteswap   *	@param hex string   *	@return decrypted string   */ -char *PianoDecryptString (const char *strInput) { -	unsigned int *cipherInts, *plainInts; -	size_t cipherIntsN; -	char *strDecrypted; - -	PianoHexToInts (strInput, &cipherInts, &cipherIntsN); -	PianoDecipherInts (cipherInts, cipherIntsN, &plainInts); -	strDecrypted = PianoIntsToString (plainInts, cipherIntsN); - -	PianoFree (cipherInts, cipherIntsN * sizeof (*cipherInts)); -	PianoFree (plainInts, cipherIntsN * sizeof (*plainInts)); - -	return strDecrypted; -} - -/*	string to int array - *	@param the string, length % 8 needs to be 0 - *	@param returns int array - *	@param returns size of int array - *	@return nothing - */ -void PianoBytesToInts (const char *strInput, unsigned int **retArrInts, -		size_t *retArrIntsN) { -	size_t i, j, neededStrLen, strInputN = strlen (strInput); -	unsigned int *arrInts; -	char shift; - -	/* blowfish encrypts two 4 byte blocks */ -	neededStrLen = strInputN; -	if (neededStrLen % 8 != 0) { -		/* substract overhead and add full 8 byte block */ -		neededStrLen = neededStrLen - (neededStrLen % 8) + 8; -	} -	arrInts = calloc (neededStrLen / 4, sizeof (*arrInts)); - -	/* we must not read beyond the end of the string, so be a bit -	 * paranoid */ -	i = 0; -	j = 0; -	while (i < strInputN) { -		shift = 24; -		while (shift >= 0 && i < strInputN) { -			arrInts[i/4] |= (strInput[i] & 0xff) << shift; -			shift -= 8; -			i++; +#define INITIAL_SHIFT 28 +#define SHIFT_DEC 4 +unsigned char *PianoDecryptString (const unsigned char *strInput) { +	/* hex-decode => strlen/2 */ +	unsigned char *strDecrypted = calloc (strlen ((char *) strInput)/2+1, sizeof (*strDecrypted)); +	uint32_t *iDecrypt = (uint32_t *) strDecrypted; +	unsigned char shift = INITIAL_SHIFT; +	unsigned char intsDecoded = 0; +	unsigned char j; +	/* blowfish blocks, 32-bit */ +	uint32_t f, l, r, lrExchange; + +	while (*strInput != '\0') { +		/* hex-decode string */ +		if (*strInput >= '0' && *strInput <= '9') { +			*iDecrypt |= (*strInput & 0x0f) << shift; +		} else if (*strInput >= 'a' && *strInput <= 'f') { +			/* 0xa (hex) = 10 (decimal), 'a' & 0x0f == 1 => +9 */ +			*iDecrypt |= ((*strInput+9) & 0x0f) << shift; +		} +		if (shift > 0) { +			shift -= SHIFT_DEC; +		} else { +			shift = INITIAL_SHIFT; +			/* initialize next dword */ +			*(++iDecrypt) = 0; +			++intsDecoded;  		} -	} -	*retArrInts = arrInts; -	*retArrIntsN = neededStrLen / 4; -} -/*	encipher ints; reverse engineered from pandora flash client - *	@param encipher this - *	@param how many ints - *	@param returns crypted ints; memory is allocated by this function - */ -void PianoEncipherInts (const unsigned int *plainInts, size_t plainIntsN, -		unsigned int **retCipherInts) { -	unsigned int *cipherInts = calloc (plainIntsN, sizeof (*cipherInts)); -	size_t i, j; -	unsigned int f, l, r, lrExchange; - -		for (i = 0; i < plainIntsN; i+=2) { -			l = plainInts [i]; -			r = plainInts [i+1]; -			 -			for (j = 0; j < out_key_n; j++) { -				l ^= out_key_p[j]; - -				f = out_key_s[0][(l >> 24) & 0xff] + -						out_key_s [1][(l >> 16) & 0xff]; -				f ^= out_key_s [2][(l >> 8) & 0xff]; -				f += out_key_s [3][l & 0xff]; +		/* two 32-bit hex-decoded boxes available => blowfish decrypt */ +		if (intsDecoded == 2) { +			l = *(iDecrypt-2); +			r = *(iDecrypt-1); + +			for (j = in_key_n + 1; j > 1; --j) { +				l ^= in_key_p [j]; +				 +				f = in_key_s [0][(l >> 24) & 0xff] + +						in_key_s [1][(l >> 16) & 0xff]; +				f ^= in_key_s [2][(l >> 8) & 0xff]; +				f += in_key_s [3][l & 0xff];  				r ^= f;  				/* exchange l & r */  				lrExchange = l;  				l = r;  				r = lrExchange;  			} -			/* exchange l & r again */ +			/* exchange l & r */  			lrExchange = l;  			l = r;  			r = lrExchange; -			r ^= out_key_p [out_key_n]; -			l ^= out_key_p [out_key_n+1]; -			cipherInts [i] = l; -			cipherInts [i+1] = r; -		} -	*retCipherInts = cipherInts; -} +			r ^= in_key_p [1]; +			l ^= in_key_p [0]; -/*	int array to hex-encoded string - *	@param int array - *	@param size of array - *	@return string; memory is allocated here, don't forget to free it - */ -char *PianoIntsToHexString (const unsigned int *arrInts, size_t arrIntsN) { -	/* 4 bytes as hex (= 8 chars) */ -	char *hexStr = calloc (arrIntsN * 4 * 2 + 1, sizeof (*hexStr)); -	size_t i, writePos; -	unsigned char *intMap = (unsigned char *) arrInts; -	size_t intMapN = arrIntsN * sizeof (*arrInts); - -	for (i = 0; i < intMapN; i++) { -		writePos = i + (4 - (i % 4) * 2) - 1; -		/* we need to swap the bytes again */ -		hexStr[writePos*2] = (intMap[i] & 0xf0) < 0xa0 ? (intMap[i] >> 4) + -				'0' : (intMap[i] >> 4) + 'a' - 10; -		hexStr[writePos*2+1] = (intMap[i] & 0x0f) < 0x0a ? (intMap[i] & 0x0f) + -				'0' : (intMap[i] & 0x0f) + 'a' - 10; +			*(iDecrypt-2) = byteswap32 (l); +			*(iDecrypt-1) = byteswap32 (r); + +			intsDecoded = 0; +		} +		++strInput;  	} -	return hexStr; + +	return strDecrypted;  } +#undef INITIAL_SHIFT +#undef SHIFT_DEC -/*	blowfish-encrypt string; used before sending xml to server +/*	blowfish-encrypt/hex-encode string   *	@param encrypt this   *	@return encrypted, hex-encoded string   */ -char *PianoEncryptString (const char *strInput) { -	unsigned int *plainInts, *cipherInts; -	size_t plainIntsN; -	char *strHex; +unsigned char *PianoEncryptString (const unsigned char *strInput) { +	size_t strInputN = strlen ((char *) strInput); +	/* num of 64-bit blocks, rounded to next block */ +	size_t blockN = strInputN / 8 + 1; +	uint32_t *blockInput = calloc (blockN*2, sizeof (*blockInput)), *blockPtr = blockInput; +	/* encryption blocks */ +	uint32_t f, lrExchange; +	register uint32_t l, r; +	/* output string */ +	unsigned char *strHex = calloc (blockN*8*2 + 1, sizeof (*strHex)), *hexPtr = strHex; +	const char *hexmap = "0123456789abcdef"; +	size_t i; -	PianoBytesToInts (strInput, &plainInts, &plainIntsN); -	PianoEncipherInts (plainInts, plainIntsN, &cipherInts); -	strHex = PianoIntsToHexString (cipherInts, plainIntsN); +	memcpy (blockInput, strInput, strInputN); + +	while (blockN > 0) { +		l = byteswap32 (*blockPtr); +		r = byteswap32 (*(blockPtr+1)); +		 +		/* encrypt blocks */ +		for (i = 0; i < out_key_n; i++) { +			l ^= out_key_p[i]; + +			f = out_key_s[0][(l >> 24) & 0xff] + +					out_key_s[1][(l >> 16) & 0xff]; +			f ^= out_key_s[2][(l >> 8) & 0xff]; +			f += out_key_s[3][l & 0xff]; +			r ^= f; +			/* exchange l & r */ +			lrExchange = l; +			l = r; +			r = lrExchange; +		} +		/* exchange l & r again */ +		lrExchange = l; +		l = r; +		r = lrExchange; +		r ^= out_key_p [out_key_n]; +		l ^= out_key_p [out_key_n+1]; + +		/* swap bytes again... */ +		l = byteswap32 (l); +		r = byteswap32 (r); + +		/* hex-encode encrypted blocks */ +		for (i = 0; i < 4; i++) { +			*hexPtr++ = hexmap[(l & 0xf0) >> 4]; +			*hexPtr++ = hexmap[l & 0x0f]; +			l >>= 8; +		} +		for (i = 0; i < 4; i++) { +			*hexPtr++ = hexmap[(r & 0xf0) >> 4]; +			*hexPtr++ = hexmap[r & 0x0f]; +			r >>= 8; +		} + +		/* two! 32-bit blocks encrypted (l & r) */ +		blockPtr += 2; +		--blockN; +	} -	PianoFree (plainInts, plainIntsN * sizeof (*plainInts)); -	PianoFree (cipherInts, plainIntsN * sizeof (*cipherInts)); +	PianoFree (blockInput, 0);  	return strHex;  } | 
