summaryrefslogtreecommitdiff
path: root/libpiano
diff options
context:
space:
mode:
Diffstat (limited to 'libpiano')
-rw-r--r--libpiano/src/crypt.c311
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;
}