From: Martin Blanchard <tchaik@xxxxxxx> MD5 hashing will be needed during the authentication process. Base64 and MD5 code is now in a commun file called raop_util.c. Old Base64 files are removed but copyright is preserved. --- src/Makefile.am | 4 +- src/modules/raop/base64.c | 136 --------------------------------- src/modules/raop/base64.h | 32 -------- src/modules/raop/raop_client.c | 6 +- src/modules/raop/raop_crypto.c | 10 +-- src/modules/raop/raop_util.c | 170 +++++++++++++++++++++++++++++++++++++++++ src/modules/raop/raop_util.h | 28 +++++++ 7 files changed, 208 insertions(+), 178 deletions(-) delete mode 100644 src/modules/raop/base64.c delete mode 100644 src/modules/raop/base64.h create mode 100644 src/modules/raop/raop_util.c create mode 100644 src/modules/raop/raop_util.h diff --git a/src/Makefile.am b/src/Makefile.am index e5b9131..9a1e1cf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1133,9 +1133,9 @@ librtp_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon-@ libraop_la_SOURCES = \ modules/raop/raop_client.c modules/raop/raop_client.h \ + modules/raop/raop_packet_buffer.h modules/raop/raop_packet_buffer.c \ modules/raop/raop_crypto.c modules/raop/raop_crypto.h \ - modules/raop/base64.c modules/raop/base64.h \ - modules/raop/raop_packet_buffer.h modules/raop/raop_packet_buffer.c + modules/raop/raop_util.c modules/raop/raop_util.h libraop_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS) -I$(top_srcdir)/src/modules/rtp libraop_la_LDFLAGS = $(AM_LDFLAGS) $(AM_LIBLDFLAGS) -avoid-version libraop_la_LIBADD = $(AM_LIBADD) $(OPENSSL_LIBS) libpulsecore- at PA_MAJORMINOR@.la librtp.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la diff --git a/src/modules/raop/base64.c b/src/modules/raop/base64.c deleted file mode 100644 index d541745..0000000 --- a/src/modules/raop/base64.c +++ /dev/null @@ -1,136 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2008 Colin Guthrie - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. -***/ - -/*** - This file was originally inspired by a file developed by - Kungliga Tekniska Høgskolan. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <string.h> - -#include <pulse/xmalloc.h> - -#include "base64.h" - -static const char base64_chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static int pos(char c) { - if (c >= 'A' && c <= 'Z') - return c - 'A' + 0; - if (c >= 'a' && c <= 'z') - return c - 'a' + 26; - if (c >= '0' && c <= '9') - return c - '0' + 52; - if (c == '+') - return 62; - if (c == '/') - return 63; - - return -1; -} - -int pa_base64_encode(const void *data, int size, char **str) { - char *s, *p; - int i; - int c; - const unsigned char *q; - - p = s = pa_xnew(char, size * 4 / 3 + 4); - q = (const unsigned char *) data; - for (i = 0; i < size;) { - c = q[i++]; - c *= 256; - if (i < size) - c += q[i]; - i++; - c *= 256; - if (i < size) - c += q[i]; - i++; - p[0] = base64_chars[(c & 0x00fc0000) >> 18]; - p[1] = base64_chars[(c & 0x0003f000) >> 12]; - p[2] = base64_chars[(c & 0x00000fc0) >> 6]; - p[3] = base64_chars[(c & 0x0000003f) >> 0]; - if (i > size) - p[3] = '='; - if (i > size + 1) - p[2] = '='; - p += 4; - } - - *p = 0; - *str = s; - - return strlen(s); -} - -#define DECODE_ERROR 0xffffffff - -static unsigned int token_decode(const char *token) { - int i; - unsigned int val = 0; - int marker = 0; - - if (strlen(token) < 4) - return DECODE_ERROR; - for (i = 0; i < 4; i++) { - val *= 64; - if (token[i] == '=') - marker++; - else if (marker > 0) - return DECODE_ERROR; - else { - int lpos = pos(token[i]); - if (lpos < 0) - return DECODE_ERROR; - val += lpos; - } - } - - if (marker > 2) - return DECODE_ERROR; - - return (marker << 24) | val; -} - -int pa_base64_decode(const char *str, void *data) { - const char *p; - unsigned char *q; - - q = data; - for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) { - unsigned int val = token_decode(p); - unsigned int marker = (val >> 24) & 0xff; - if (val == DECODE_ERROR) - return -1; - *q++ = (val >> 16) & 0xff; - if (marker < 2) - *q++ = (val >> 8) & 0xff; - if (marker < 1) - *q++ = val & 0xff; - } - - return q - (unsigned char *) data; -} diff --git a/src/modules/raop/base64.h b/src/modules/raop/base64.h deleted file mode 100644 index ce6b9c4..0000000 --- a/src/modules/raop/base64.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef foobase64hfoo -#define foobase64hfoo - -/*** - This file is part of PulseAudio. - - Copyright 2008 Colin Guthrie - Copyright Kungliga Tekniska Høgskolan - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. -***/ - -/*** - This file was originally inspired by a file developed by - Kungliga Tekniska Høgskolan. -***/ - -int pa_base64_encode(const void *data, int size, char **str); -int pa_base64_decode(const char *str, void *data); - -#endif diff --git a/src/modules/raop/raop_client.c b/src/modules/raop/raop_client.c index 5c825eb..a2ec91e 100644 --- a/src/modules/raop/raop_client.c +++ b/src/modules/raop/raop_client.c @@ -53,7 +53,7 @@ #include "rtsp_client.h" #include "raop_packet_buffer.h" #include "raop_crypto.h" -#include "base64.h" +#include "raop_util.h" #define JACK_STATUS_DISCONNECTED 0 #define JACK_STATUS_CONNECTED 1 @@ -528,7 +528,7 @@ static void do_rtsp_announce(pa_raop_client *c) { /* UDP protocol does not need "Apple-Challenge" at announce. */ if (c->protocol == RAOP_TCP) { pa_random(&rand_data, sizeof(rand_data)); - pa_base64_encode(&rand_data, sizeof(rand_data), &sac); + pa_raop_base64_encode(&rand_data, 8*sizeof(rand_data), &sac); rtrimchar(sac, '='); pa_rtsp_add_header(c->rtsp, "Apple-Challenge", sac); } @@ -689,7 +689,7 @@ static void udp_rtsp_cb(pa_rtsp_client *rtsp, pa_rtsp_state state, pa_headerlist /* Set the Apple-Challenge key */ pa_random(&rand, sizeof(rand)); - pa_base64_encode(&rand, sizeof(rand), &sac); + pa_raop_base64_encode(&rand, 8*sizeof(rand), &sac); rtrimchar(sac, '='); pa_rtsp_add_header(c->rtsp, "Apple-Challenge", sac); diff --git a/src/modules/raop/raop_crypto.c b/src/modules/raop/raop_crypto.c index cd2934b..eacf392 100644 --- a/src/modules/raop/raop_crypto.c +++ b/src/modules/raop/raop_crypto.c @@ -37,7 +37,7 @@ #include <pulsecore/random.h> #include "raop_crypto.h" -#include "base64.h" +#include "raop_util.h" #define AES_CHUNK_SIZE 16 @@ -68,9 +68,9 @@ static int rsa_encrypt(uint8_t *data, int len, uint8_t *str) { pa_assert(str); rsa = RSA_new(); - size = pa_base64_decode(rsa_modulus, modules); + size = pa_raop_base64_decode(rsa_modulus, modules); rsa->n = BN_bin2bn(modules, size, NULL); - size = pa_base64_decode(rsa_exponent, exponent); + size = pa_raop_base64_decode(rsa_exponent, exponent); rsa->e = BN_bin2bn(exponent, size, NULL); size = RSA_public_encrypt(len, data, str, rsa, RSA_PKCS1_OAEP_PADDING); @@ -102,7 +102,7 @@ char* pa_raop_secret_get_iv(pa_raop_secret *s) { pa_assert(s); - pa_base64_encode(s->iv, AES_CHUNK_SIZE, &base64_iv); + pa_raop_base64_encode(s->iv, AES_CHUNK_SIZE, &base64_iv); return base64_iv; } @@ -116,7 +116,7 @@ char* pa_raop_secret_get_key(pa_raop_secret *s) { /* Encrypt our AES public key to send to the device */ size = rsa_encrypt(s->key, AES_CHUNK_SIZE, rsa_key); - pa_base64_encode(rsa_key, size, &base64_key); + pa_raop_base64_encode(rsa_key, size, &base64_key); return base64_key; } diff --git a/src/modules/raop/raop_util.c b/src/modules/raop/raop_util.c new file mode 100644 index 0000000..54f7c6d --- /dev/null +++ b/src/modules/raop/raop_util.c @@ -0,0 +1,170 @@ +/*** + This file is part of PulseAudio. + + Copyright 2013 Martin Blanchard + Copyright Kungliga Tekniska Høgskolan & Colin Guthrie + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. +***/ + +/*** + The base64 implementation was originally inspired by a file developed + by Kungliga Tekniska Høgskolan. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#include <openssl/err.h> +#include <openssl/md5.h> + +#include <pulse/xmalloc.h> + +#include <pulsecore/macro.h> + +#include "raop_util.h" + +#ifndef MD5_DIGEST_LENGTH +#define MD5_DIGEST_LENGTH 16 +#endif + +#define MD5_HASH_LENGTH (2*MD5_DIGEST_LENGTH) + +#define BASE64_DECODE_ERROR 0xffffffff + +static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int char_position(char c) { + if (c >= 'A' && c <= 'Z') + return c - 'A' + 0; + if (c >= 'a' && c <= 'z') + return c - 'a' + 26; + if (c >= '0' && c <= '9') + return c - '0' + 52; + if (c == '+') + return 62; + if (c == '/') + return 63; + + return -1; +} + +static unsigned int token_decode(const char *token) { + unsigned int val = 0; + int marker = 0; + int i; + + if (strlen(token) < 4) + return BASE64_DECODE_ERROR; + for (i = 0; i < 4; i++) { + val *= 64; + if (token[i] == '=') + marker++; + else if (marker > 0) + return BASE64_DECODE_ERROR; + else { + int lpos = char_position(token[i]); + if (lpos < 0) + return BASE64_DECODE_ERROR; + val += lpos; + } + } + + if (marker > 2) + return BASE64_DECODE_ERROR; + + return (marker << 24) | val; +} + +int pa_raop_base64_encode(const void *data, int len, char **str) { + const unsigned char *q; + char *p, *s = NULL; + int i, c; + + pa_assert(data); + pa_assert(str); + + p = s = pa_xnew(char, len * 4 / 3 + 4); + q = (const unsigned char *) data; + for (i = 0; i < len;) { + c = q[i++]; + c *= 256; + if (i < len) + c += q[i]; + i++; + c *= 256; + if (i < len) + c += q[i]; + i++; + p[0] = base64_chars[(c & 0x00fc0000) >> 18]; + p[1] = base64_chars[(c & 0x0003f000) >> 12]; + p[2] = base64_chars[(c & 0x00000fc0) >> 6]; + p[3] = base64_chars[(c & 0x0000003f) >> 0]; + if (i > len) + p[3] = '='; + if (i > len + 1) + p[2] = '='; + p += 4; + } + + *p = 0; + *str = s; + return strlen(s); +} + +int pa_raop_base64_decode(const char *str, void *data) { + const char *p; + unsigned char *q; + + pa_assert(str); + pa_assert(data); + + q = data; + for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) { + unsigned int val = token_decode(p); + unsigned int marker = (val >> 24) & 0xff; + if (val == BASE64_DECODE_ERROR) + return -1; + *q++ = (val >> 16) & 0xff; + if (marker < 2) + *q++ = (val >> 8) & 0xff; + if (marker < 1) + *q++ = val & 0xff; + } + + return q - (unsigned char *) data; +} + +int pa_raop_md5_hash(const char *data, int len, char **str) { + unsigned char d[MD5_DIGEST_LENGTH]; + char *s = NULL; + int i; + + pa_assert(data); + pa_assert(str); + + MD5((unsigned char*) data, len, d); + s = pa_xnew(char, MD5_HASH_LENGTH); + for (i = 0; i < MD5_DIGEST_LENGTH; i++) + sprintf(&s[2*i], "%02x", (unsigned int) d[i]); + + *str = s; + s[MD5_HASH_LENGTH] = 0; + return strlen(s); +} diff --git a/src/modules/raop/raop_util.h b/src/modules/raop/raop_util.h new file mode 100644 index 0000000..a95c822 --- /dev/null +++ b/src/modules/raop/raop_util.h @@ -0,0 +1,28 @@ +#ifndef fooraoputilfoo +#define fooraoputilfoo + +/*** + This file is part of PulseAudio. + + Copyright 2013 Martin Blanchard + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. +***/ + +int pa_raop_base64_encode(const void *data, int len, char **str); +int pa_raop_base64_decode(const char *str, void *data); + +int pa_raop_md5_hash(const char *data, int len, char **str); + +#endif -- 2.5.0