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; } |