diff --git a/daemon/src/audio/audiortp/Makefile.am b/daemon/src/audio/audiortp/Makefile.am index 7fa1062641149206869840bf7b9f5737754667d9..642f365a1ad8c65078b48cfd7e4bff82ec8d047f 100644 --- a/daemon/src/audio/audiortp/Makefile.am +++ b/daemon/src/audio/audiortp/Makefile.am @@ -19,4 +19,5 @@ libaudiortp_la_SOURCES = \ audio_rtp_stream.h \ audio_rtp_factory.h \ audio_symmetric_rtp_session.h \ - audio_srtp_session.h + audio_srtp_session.h \ + base64.c base64.h diff --git a/daemon/src/audio/audiortp/audio_srtp_session.cpp b/daemon/src/audio/audiortp/audio_srtp_session.cpp index 00f432eca63bd8dba5e7da092ba526a7136de269..0d108ba886c34c16055be1574237ea5a214a95d1 100644 --- a/daemon/src/audio/audiortp/audio_srtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_srtp_session.cpp @@ -30,15 +30,10 @@ #include "audio_srtp_session.h" #include "logger.h" #include "array_size.h" +#include "base64.h" #include <algorithm> - -#include <openssl/sha.h> -#include <openssl/hmac.h> -#include <openssl/evp.h> -#include <openssl/bio.h> -#include <openssl/buffer.h> -#include <openssl/rand.h> +#include <random> #include <cstdio> #include <cstring> @@ -51,53 +46,27 @@ namespace sfl { namespace { -std::string -encodeBase64(unsigned char *input, int length) -{ - // init decoder - BIO *b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - - // init internal buffer - BIO *bmem = BIO_new(BIO_s_mem()); - - // create decoder chain - b64 = BIO_push(b64, bmem); - - BIO_write(b64, input, length); - // BIO_flush (b64); - - // get pointer to data - BUF_MEM *bptr = 0; - BIO_get_mem_ptr(b64, &bptr); - - std::string output(bptr->data, bptr->length); - - BIO_free_all(bmem); +std::string encodeBase64(unsigned char *input, int length) +{ + size_t output_length; + uint8_t *encoded_str = base64_encode(input, length, &output_length); + if (!encoded_str) + THROW_ERROR(AudioSrtpException, "Out of memory for base64 operation"); + std::string output((const char *)encoded_str, output_length); + free(encoded_str); return output; } -std::vector<char> decodeBase64(unsigned char *input, int length) +std::string decodeBase64(unsigned char *input, int length) { - BIO *b64, *bmem; - - // init decoder and read-only BIO buffer - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - - // init internal buffer - bmem = BIO_new_mem_buf(input, length); - - // create encoder chain - bmem = BIO_push(b64, bmem); - - std::vector<char> buffer(length, 0); - BIO_read(bmem, buffer.data(), length); - - BIO_free_all(bmem); - - return buffer; + size_t output_length; + uint8_t *decoded_str = base64_decode(input, length, &output_length); + if (!decoded_str) + THROW_ERROR(AudioSrtpException, "Out of memory for base64 operation"); + std::string output((const char *)decoded_str, output_length); + free(decoded_str); + return output; } // Fills the array dest with length random bytes @@ -105,12 +74,16 @@ void bufferFillMasterKey(std::vector<uint8>& dest) { DEBUG("Init local master key"); + // Prepare pseudo random generationusing Mersenne Twister + std::mt19937 eng; + std::uniform_int_distribution<uint8_t> dist(0, 255); + // Allocate memory for key std::vector<unsigned char> random_key(dest.size()); - // Generate ryptographically strong pseudo-random bytes - if (RAND_bytes(random_key.data(), dest.size()) != 1) - DEBUG("Error occured while generating cryptographically strong pseudo-random key"); + // Fill the key + for (int i = 0; i < dest.size(); i++) + random_key[i] = dist(eng); std::copy(random_key.begin(), random_key.end(), dest.begin()); } @@ -118,14 +91,18 @@ void bufferFillMasterKey(std::vector<uint8>& dest) // Fills the array dest with length random bytes void bufferFillMasterSalt(std::vector<uint8>& dest) { - DEBUG("Init local master key"); + DEBUG("Init local master salt"); + + // Prepare pseudo random generation using Mersenne Twister + std::mt19937 eng; + std::uniform_int_distribution<uint8_t> dist(0, 255); // Allocate memory for key std::vector<unsigned char> random_key(dest.size()); - // Generate ryptographically strong pseudo-random bytes - if (RAND_bytes(random_key.data(), dest.size()) != 1) - DEBUG("Error occured while generating cryptographically strong pseudo-random key"); + // Fill the key + for (int i = 0; i < dest.size(); i++) + random_key[i] = dist(eng); std::copy(random_key.begin(), random_key.end(), dest.begin()); } @@ -276,14 +253,11 @@ void AudioSrtpSession::unBase64ConcatenatedKeys(std::string base64keys) remoteMasterKey_.resize(sfl::CryptoSuites[remoteCryptoSuite_].masterKeyLength / BITS_PER_BYTE); remoteMasterSalt_.resize(sfl::CryptoSuites[remoteCryptoSuite_].masterSaltLength / BITS_PER_BYTE); - // pointer to binary data - char *dataptr = (char*) base64keys.data(); - // decode concatenated binary keys - std::vector<char> output(decodeBase64((unsigned char*) dataptr, strlen(dataptr))); + std::string output(decodeBase64((uint8_t *)base64keys.data(), base64keys.size())); // copy master and slt respectively - const std::vector<char>::iterator key_end = output.begin() + remoteMasterKey_.size(); + const std::string::iterator key_end = output.begin() + remoteMasterKey_.size(); if (key_end > output.end() or (size_t) std::distance(key_end, output.end()) > remoteMasterSalt_.size()) diff --git a/daemon/src/audio/audiortp/base64.c b/daemon/src/audio/audiortp/base64.c new file mode 100644 index 0000000000000000000000000000000000000000..5ed7b29a7d489b53366cf690d970a1b30fe630f6 --- /dev/null +++ b/daemon/src/audio/audiortp/base64.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * This program 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 General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include <stdint.h> +#include <stdlib.h> + +/* Mainly based on the following stackoverflow question: + * http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c + */ +static const uint8_t encoding_table[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +static const int mod_table[] = { 0, 2, 1 }; + +uint8_t *base64_encode(const uint8_t *data, + size_t input_length, size_t *output_length) +{ + int i, j; + uint8_t *encoded_data; + *output_length = 4 * ((input_length + 2) / 3); + + encoded_data = (uint8_t *)malloc(*output_length); + if (encoded_data == NULL) + return NULL; + + for (i = 0, j = 0; i < input_length; ) { + uint8_t octet_a = i < input_length ? data[i++] : 0; + uint8_t octet_b = i < input_length ? data[i++] : 0; + uint8_t octet_c = i < input_length ? data[i++] : 0; + + uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; + } + + for (i = 0; i < mod_table[input_length % 3]; i++) + encoded_data[*output_length - 1 - i] = '='; + + return encoded_data; +} + +uint8_t *base64_decode(const uint8_t *data, + size_t input_length, size_t *output_length) +{ + int i, j; + uint8_t decoding_table[256]; + unsigned char *decoded_data; + + for (i = 0; i < 64; i++) + decoding_table[(uint8_t) encoding_table[i]] = i; + + if (input_length % 4 != 0) + return NULL; + + *output_length = input_length / 4 * 3; + if (data[input_length - 1] == '=') + (*output_length)--; + if (data[input_length - 2] == '=') + (*output_length)--; + + decoded_data = (unsigned char *)malloc(*output_length); + if (decoded_data == NULL) + return NULL; + + for (i = 0, j = 0; i < input_length;) { + uint8_t sextet_a = data[i] == '=' ? 0 & i++ + : decoding_table[data[i++]]; + uint8_t sextet_b = data[i] == '=' ? 0 & i++ + : decoding_table[data[i++]]; + uint8_t sextet_c = data[i] == '=' ? 0 & i++ + : decoding_table[data[i++]]; + uint8_t sextet_d = data[i] == '=' ? 0 & i++ + : decoding_table[data[i++]]; + + uint32_t triple = (sextet_a << 3 * 6) + + (sextet_b << 2 * 6) + + (sextet_c << 1 * 6) + + (sextet_d << 0 * 6); + + if (j < *output_length) + decoded_data[j++] = (triple >> 2 * 8) & 0xFF; + if (j < *output_length) + decoded_data[j++] = (triple >> 1 * 8) & 0xFF; + if (j < *output_length) + decoded_data[j++] = (triple >> 0 * 8) & 0xFF; + } + + return decoded_data; +} diff --git a/daemon/src/audio/audiortp/base64.h b/daemon/src/audio/audiortp/base64.h new file mode 100644 index 0000000000000000000000000000000000000000..482ad4e64f3a753e781d9619e0f930f11367a3d8 --- /dev/null +++ b/daemon/src/audio/audiortp/base64.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * This program 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 General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef H_BASE64 +#define H_BASE64 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdint.h" + +/** + * Encode a buffer in base64. + * + * @param data the input buffer + * @param input_length the input length + * @param output_length the resulting output length + * @return a base64-encoded buffer + * + * @note callers should free the returned memory + */ +uint8_t *base64_encode(const uint8_t *data, + size_t input_length, size_t *output_length); + +/** + * Decode a base64 buffer. + * + * @param data the input buffer + * @param input_length the input length + * @param output_length the resulting output length + * @return a buffer + * + * @note callers should free the returned memory + */ +uint8_t *base64_decode(const uint8_t *data, + size_t input_length, size_t *output_length); + +#ifdef __cplusplus +} +#endif + +#endif // H_BASE64