From a3bae55d41f5159df3a0125f02a8fa322e81bbe3 Mon Sep 17 00:00:00 2001 From: Michał Cichoń Date: Tue, 25 Aug 2015 06:45:41 +0200 Subject: libpiano: Abstract out blowfish cipher to PianoCipher_t so different implementations than gcrypt can be used. --- src/config.h | 33 ++++++++++------------------- src/libpiano/crypt.c | 55 +++++++++++++++++++++++++++++++++++++++---------- src/libpiano/crypt.h | 13 ++++++------ src/libpiano/piano.c | 33 +++++++++++++---------------- src/libpiano/piano.h | 11 +++++----- src/libpiano/request.c | 6 +++--- src/libpiano/response.c | 4 ++-- 7 files changed, 86 insertions(+), 69 deletions(-) diff --git a/src/config.h b/src/config.h index 788455c..2d335a9 100644 --- a/src/config.h +++ b/src/config.h @@ -6,32 +6,21 @@ #define VERSION "2014.09.28-dev" -/* glibc feature test macros, define _before_ including other files */ -#define _POSIX_C_SOURCE 200809L - -/* ffmpeg/libav quirks detection - * ffmpeg’s micro versions always start at 100, that’s how we can distinguish - * ffmpeg and libav */ -#include - -/* is "timeout" option present (all versions of ffmpeg, not libav) */ -#if LIBAVFILTER_VERSION_MICRO >= 100 -#define HAVE_AV_TIMEOUT +/* Visual C++ name restrict differently */ +#ifdef _WIN32 +#define restrict __restrict #endif -/* does graph_send_command exist (ffmpeg >=2.2) */ -#if LIBAVFILTER_VERSION_MAJOR >= 4 && \ - LIBAVFILTER_VERSION_MICRO >= 100 -#define HAVE_AVFILTER_GRAPH_SEND_COMMAND +/* Visual C++ does not have inline keyword in C */ +#ifdef _WIN32 +#define inline __inline #endif -/* need avcodec.h (ffmpeg 1.2) */ -#if LIBAVFILTER_VERSION_MAJOR == 3 && \ - LIBAVFILTER_VERSION_MINOR <= 42 && \ - LIBAVFILTER_VERSION_MINOR > 32 && \ - LIBAVFILTER_VERSION_MICRO >= 100 -#define HAVE_AV_BUFFERSINK_GET_BUFFER_REF -#define HAVE_LIBAVFILTER_AVCODEC_H +/* Visual C++ does not have strcasecmp */ +#ifdef _WIN32 +#define strcasecmp _stricmp #endif +#define CURL_STATICLIB + #endif /* SRC_CONFIG_H_S6A1C09K */ diff --git a/src/libpiano/crypt.c b/src/libpiano/crypt.c index 8886f17..e203812 100644 --- a/src/libpiano/crypt.c +++ b/src/libpiano/crypt.c @@ -29,17 +29,50 @@ THE SOFTWARE. #include "crypt.h" +#include + +struct _PianoCipher_t { + BLOWFISH_CTX cipher; +}; + +PianoReturn_t PianoCryptInit (PianoCipher_t* h, const char * const key, + size_t const size) { + PianoCipher_t result = malloc (sizeof(BLOWFISH_CTX)); + if (result == NULL) { + return PIANO_RET_OUT_OF_MEMORY; + } + + Blowfish_Init (&result->cipher, (unsigned char*)key, size); + + *h = result; + + return PIANO_RET_OK; +} + +void PianoCryptDestroy (PianoCipher_t h) { + free(h); +} + +static inline bool PianoCryptDecrypt (PianoCipher_t h, unsigned char* output, size_t size) { + return Blowfish_DecryptData (&h->cipher, (uint32_t*)output, (uint32_t*)output, size) == BLOWFISH_OK; +} + +static inline bool PianoCryptEncrypt (PianoCipher_t h, unsigned char* output, size_t size) +{ + return Blowfish_EncryptData (&h->cipher, (uint32_t*)output, (uint32_t*)output, size) == BLOWFISH_OK; +} + /* decrypt hex-encoded, blowfish-crypted string: decode 2 hex-encoded blocks, * decrypt, byteswap - * @param gcrypt handle + * @param cipher handle * @param hex string * @param decrypted string length (without trailing NUL) * @return decrypted string or NULL */ -char *PianoDecryptString (gcry_cipher_hd_t h, const char * const input, +char *PianoDecryptString (PianoCipher_t h, const char * const input, size_t * const retSize) { size_t inputLen = strlen (input); - gcry_error_t gret; + bool ret; unsigned char *output; size_t outputLen = inputLen/2; @@ -51,11 +84,11 @@ char *PianoDecryptString (gcry_cipher_hd_t h, const char * const input, char hex[3]; memcpy (hex, &input[i*2], 2); hex[2] = '\0'; - output[i] = strtol (hex, NULL, 16); + output[i] = (unsigned char) strtol (hex, NULL, 16); } - gret = gcry_cipher_decrypt (h, output, outputLen, NULL, 0); - if (gret) { + ret = PianoCryptDecrypt (h, output, outputLen); + if (!ret) { free (output); return NULL; } @@ -66,22 +99,22 @@ char *PianoDecryptString (gcry_cipher_hd_t h, const char * const input, } /* blowfish-encrypt/hex-encode string - * @param gcrypt handle + * @param cipher handle * @param encrypt this * @return encrypted, hex-encoded string */ -char *PianoEncryptString (gcry_cipher_hd_t h, const char *s) { +char *PianoEncryptString (PianoCipher_t h, const char *s) { unsigned char *paddedInput, *hexOutput; size_t inputLen = strlen (s); /* blowfish expects two 32 bit blocks */ size_t paddedInputLen = (inputLen % 8 == 0) ? inputLen : inputLen + (8-inputLen%8); - gcry_error_t gret; + bool ret; paddedInput = calloc (paddedInputLen+1, sizeof (*paddedInput)); memcpy (paddedInput, s, inputLen); - gret = gcry_cipher_encrypt (h, paddedInput, paddedInputLen, NULL, 0); - if (gret) { + ret = PianoCryptEncrypt (h, paddedInput, paddedInputLen); + if (!ret) { free (paddedInput); return NULL; } diff --git a/src/libpiano/crypt.h b/src/libpiano/crypt.h index fc7c205..890b8c1 100644 --- a/src/libpiano/crypt.h +++ b/src/libpiano/crypt.h @@ -24,13 +24,14 @@ THE SOFTWARE. #ifndef SRC_LIBPIANO_CRYPT_H_O832IVGK #define SRC_LIBPIANO_CRYPT_H_O832IVGK -#ifdef __FreeBSD__ -#define _GCRYPT_IN_LIBGCRYPT -#endif -#include +#include "piano.h" -char *PianoDecryptString (gcry_cipher_hd_t, const char * const, +PianoReturn_t PianoCryptInit (PianoCipher_t*, const char * const, + size_t const); +void PianoCryptDestroy (PianoCipher_t); + +char *PianoDecryptString (PianoCipher_t, const char * const, size_t * const); -char *PianoEncryptString (gcry_cipher_hd_t, const char *); +char *PianoEncryptString (PianoCipher_t, const char *); #endif /* SRC_LIBPIANO_CRYPT_H_O832IVGK */ diff --git a/src/libpiano/piano.c b/src/libpiano/piano.c index 72502f7..c496ea1 100644 --- a/src/libpiano/piano.c +++ b/src/libpiano/piano.c @@ -31,6 +31,7 @@ THE SOFTWARE. #include "piano_private.h" #include "piano.h" +#include "crypt.h" /* initialize piano handle * @param piano handle @@ -39,30 +40,24 @@ THE SOFTWARE. PianoReturn_t PianoInit (PianoHandle_t *ph, const char *partnerUser, const char *partnerPassword, const char *device, const char *inkey, const char *outkey) { + PianoReturn_t ret = PIANO_RET_OK; + memset (ph, 0, sizeof (*ph)); ph->partner.user = strdup (partnerUser); ph->partner.password = strdup (partnerPassword); ph->partner.device = strdup (device); - if (gcry_cipher_open (&ph->partner.in, GCRY_CIPHER_BLOWFISH, - GCRY_CIPHER_MODE_ECB, 0) != GPG_ERR_NO_ERROR) { - return PIANO_RET_GCRY_ERR; - } - if (gcry_cipher_setkey (ph->partner.in, (const unsigned char *) inkey, - strlen (inkey)) != GPG_ERR_NO_ERROR) { - return PIANO_RET_GCRY_ERR; + ret = PianoCryptInit (&ph->partner.in, inkey, strlen (inkey)); + if (ret != PIANO_RET_OK) { + return ret; } - if (gcry_cipher_open (&ph->partner.out, GCRY_CIPHER_BLOWFISH, - GCRY_CIPHER_MODE_ECB, 0) != GPG_ERR_NO_ERROR) { - return PIANO_RET_GCRY_ERR; - } - if (gcry_cipher_setkey (ph->partner.out, (const unsigned char *) outkey, - strlen (outkey)) != GPG_ERR_NO_ERROR) { - return PIANO_RET_GCRY_ERR; + ret = PianoCryptInit (&ph->partner.out, outkey, strlen(outkey)); + if (ret != PIANO_RET_OK) { + return ret; } - return PIANO_RET_OK; + return ret; } /* destroy artist linked list @@ -178,8 +173,8 @@ static void PianoDestroyPartner (PianoPartner_t *partner) { free (partner->password); free (partner->device); free (partner->authToken); - gcry_cipher_close (partner->in); - gcry_cipher_close (partner->out); + PianoCryptDestroy (partner->in); + PianoCryptDestroy (partner->out); memset (partner, 0, sizeof (*partner)); } @@ -267,8 +262,8 @@ const char *PianoErrorToStr (PianoReturn_t ret) { return "Selected audio quality is not available."; break; - case PIANO_RET_GCRY_ERR: - return "libgcrypt initialization failed."; + case PIANO_RET_CIPHER_ERR: + return "Cipher initialization failed."; break; /* pandora error messages */ diff --git a/src/libpiano/piano.h b/src/libpiano/piano.h index 1a84d4a..ca33626 100644 --- a/src/libpiano/piano.h +++ b/src/libpiano/piano.h @@ -26,11 +26,8 @@ THE SOFTWARE. #include "../config.h" +#include #include -#ifdef __FreeBSD__ -#define _GCRYPT_IN_LIBGCRYPT -#endif -#include /* this is our public API; don't expect this api to be stable as long as * pandora does not provide a stable api @@ -44,6 +41,8 @@ THE SOFTWARE. #define PIANO_RPC_HOST "tuner.pandora.com" #define PIANO_RPC_PATH "/services/json/?" +typedef struct _PianoCipher_t* PianoCipher_t; + typedef struct PianoListHead { struct PianoListHead *next; } PianoListHead_t; @@ -124,7 +123,7 @@ typedef struct PianoGenreCategory { } PianoGenreCategory_t; typedef struct PianoPartner { - gcry_cipher_hd_t in, out; + PianoCipher_t in, out; char *authToken, *device, *user, *password; unsigned int id; } PianoPartner_t; @@ -276,7 +275,7 @@ typedef enum { PIANO_RET_OUT_OF_MEMORY = 4, PIANO_RET_INVALID_LOGIN = 5, PIANO_RET_QUALITY_UNAVAILABLE = 6, - PIANO_RET_GCRY_ERR = 7, + PIANO_RET_CIPHER_ERR = 7, /* pandora error codes */ PIANO_RET_P_INTERNAL = PIANO_RET_OFFSET+0, diff --git a/src/libpiano/request.c b/src/libpiano/request.c index 02b4b43..a97abb5 100644 --- a/src/libpiano/request.c +++ b/src/libpiano/request.c @@ -24,7 +24,7 @@ THE SOFTWARE. #include "../config.h" #include -#include +#include #include #include #include @@ -94,7 +94,7 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req, json_object_object_add (j, "partnerAuthToken", json_object_new_string (ph->partner.authToken)); json_object_object_add (j, "syncTime", - json_object_new_int (timestamp)); + json_object_new_int64 (timestamp)); CURL * const curl = curl_easy_init (); urlencAuthToken = curl_easy_escape (curl, @@ -487,7 +487,7 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req, json_object_object_add (j, "userAuthToken", json_object_new_string (ph->user.authToken)); json_object_object_add (j, "syncTime", - json_object_new_int (timestamp)); + json_object_new_int64 (timestamp)); } /* json to string */ diff --git a/src/libpiano/response.c b/src/libpiano/response.c index 7f0cee0..783e2f0 100644 --- a/src/libpiano/response.c +++ b/src/libpiano/response.c @@ -23,7 +23,7 @@ THE SOFTWARE. #include "../config.h" -#include +#include #include #include #include @@ -273,7 +273,7 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) { song->stationId = PianoJsonStrdup (s, "stationId"); song->coverArt = PianoJsonStrdup (s, "albumArtUrl"); song->detailUrl = PianoJsonStrdup (s, "songDetailUrl"); - song->fileGain = json_object_get_double ( + song->fileGain = (float)json_object_get_double ( json_object_object_get (s, "trackGain")); song->length = json_object_get_int ( json_object_object_get (s, "trackLength")); -- cgit v1.2.3