From 84f81983aa609d2027e290c808280428a4e69f0e Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 22 Jul 2018 17:56:38 +0800 Subject: [PATCH] Replace base64 to match MIT license. 3.0.32 --- README.md | 1 + trunk/src/core/srs_core.hpp | 2 +- trunk/src/kernel/srs_kernel_error.hpp | 1 + trunk/src/kernel/srs_kernel_utility.cpp | 300 ++++++++---------------- trunk/src/kernel/srs_kernel_utility.hpp | 21 +- trunk/src/protocol/srs_rtsp_stack.cpp | 17 +- trunk/src/utest/srs_utest_kernel.cpp | 10 + 7 files changed, 117 insertions(+), 235 deletions(-) diff --git a/README.md b/README.md index 7b7137216..f2d2d52c9 100755 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ Please select according to languages: ### V3 changes +* v3.0, 2018-07-22, Replace base64 to match MIT license. 3.0.32 * v3.0, 2018-07-22, Replace crc32 IEEE and MPEG by pycrc to match MIT license. 3.0.31 * v3.0, 2018-07-21, Replace crc32 IEEE by golang to match MIT license. 3.0.30 * v3.0, 2018-02-16, Fix [#464][bug #464], support RTMP origin cluster. 3.0.29 diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 48f3a7e30..b62795c9f 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -27,7 +27,7 @@ // current release version #define VERSION_MAJOR 3 #define VERSION_MINOR 0 -#define VERSION_REVISION 31 +#define VERSION_REVISION 32 // generated by configure, only macros. #include diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index a80dd8272..9ffc1c557 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -318,6 +318,7 @@ #define ERROR_KAFKA_CODEC_MESSAGE 4036 #define ERROR_KAFKA_CODEC_PRODUCER 4037 #define ERROR_HTTP_302_INVALID 4038 +#define ERROR_BASE64_DECODE 4039 /////////////////////////////////////////////////////// // HTTP API error. diff --git a/trunk/src/kernel/srs_kernel_utility.cpp b/trunk/src/kernel/srs_kernel_utility.cpp index 009c51bca..a247bf27d 100644 --- a/trunk/src/kernel/srs_kernel_utility.cpp +++ b/trunk/src/kernel/srs_kernel_utility.cpp @@ -830,217 +830,113 @@ uint32_t srs_crc32_mpegts(const void* buf, int size) return __crc32_table_driven(__crc32_MPEG_table, buf, size, 0x00, reflect_in, xor_in, reflect_out, xor_out); } -/* - * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) - * - * This file is part of FFmpeg. - * - * FFmpeg 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. - * - * FFmpeg 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef UINT_MAX -#define UINT_MAX 0xffffffff -#endif - -#ifndef AV_RB32 -# define AV_RB32(x) \ - (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ - (((const uint8_t*)(x))[1] << 16) | \ - (((const uint8_t*)(x))[2] << 8) | \ - ((const uint8_t*)(x))[3]) -#endif - -#ifndef AV_WL32 -# define AV_WL32(p, darg) do { \ - unsigned d = (darg); \ - ((uint8_t*)(p))[0] = (d); \ - ((uint8_t*)(p))[1] = (d)>>8; \ - ((uint8_t*)(p))[2] = (d)>>16; \ - ((uint8_t*)(p))[3] = (d)>>24; \ -} while(0) -#endif - -# define AV_WN(s, p, v) AV_WL##s(p, v) - -# if defined(AV_WN32) && !defined(AV_WL32) -# define AV_WL32(p, v) AV_WN32(p, v) -# elif !defined(AV_WN32) && defined(AV_WL32) -# define AV_WN32(p, v) AV_WL32(p, v) -# endif - -#ifndef AV_WN32 - # define AV_WN32(p, v) AV_WN(32, p, v) -#endif - -#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) -#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) - -#ifndef av_bswap32 -static const uint32_t av_bswap32(uint32_t x) +// @see golang encoding/base64/base64.go +srs_error_t srs_av_base64_decode(string cipher, string& plaintext) { - return AV_BSWAP32C(x); -} -#endif + srs_error_t err = srs_success; -#define av_be2ne32(x) av_bswap32(x) -/** - * @file - * @brief Base64 encode/decode - * @author Ryan Martell (with lots of Michael) - */ - -/* ---------------- private code */ -static const uint8_t map2[256] = -{ - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, + // We use the standard encoding: + // var StdEncoding = NewEncoding(encodeStd) + // StdEncoding is the standard base64 encoding, as defined in RFC 4648. + char padding = '='; + string encoder = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + uint8_t decodeMap[256]; + memset(decodeMap, 0xff, sizeof(decodeMap)); - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; - -#define BASE64_DEC_STEP(i) do { \ - bits = map2[in[i]]; \ - if (bits & 0x80) \ - goto out ## i; \ - v = i ? (v << 6) + bits : bits; \ -} while(0) - -int srs_av_base64_decode(uint8_t* out, const char* in_str, int out_size) -{ - uint8_t *dst = out; - uint8_t *end = out + out_size; - // no sign extension - const uint8_t *in = (const uint8_t*)in_str; - unsigned bits = 0xff; - unsigned v = 0; - - while (end - dst > 3) { - BASE64_DEC_STEP(0); - BASE64_DEC_STEP(1); - BASE64_DEC_STEP(2); - BASE64_DEC_STEP(3); - // Using AV_WB32 directly confuses compiler - v = av_be2ne32(v << 8); - AV_WN32(dst, v); - dst += 3; - in += 4; - } - if (end - dst) { - BASE64_DEC_STEP(0); - BASE64_DEC_STEP(1); - BASE64_DEC_STEP(2); - BASE64_DEC_STEP(3); - *dst++ = v >> 16; - if (end - dst) - *dst++ = v >> 8; - if (end - dst) - *dst++ = v; - in += 4; - } - while (1) { - BASE64_DEC_STEP(0); - in++; - BASE64_DEC_STEP(0); - in++; - BASE64_DEC_STEP(0); - in++; - BASE64_DEC_STEP(0); - in++; + for (int i = 0; i < encoder.length(); i++) { + decodeMap[(uint8_t)encoder.at(i)] = uint8_t(i); } -out3: - *dst++ = v >> 10; - v <<= 2; -out2: - *dst++ = v >> 4; -out1: -out0: - return bits & 1 ? -1 : (int)(dst - out); -} - -/***************************************************************************** - * b64_encode: Stolen from VLC's http.c. - * Simplified by Michael. - * Fixed edge cases and made it work from data (vs. strings) by Ryan. - *****************************************************************************/ -char* srs_av_base64_encode(char* out, int out_size, const uint8_t* in, int in_size) -{ - static const char b64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - char *ret, *dst; - unsigned i_bits = 0; - int i_shift = 0; - int bytes_remaining = in_size; + // decode is like Decode but returns an additional 'end' value, which + // indicates if end-of-message padding or a partial quantum was encountered + // and thus any additional data is an error. + int si = 0; - if (in_size >= (int)(UINT_MAX / 4) || - out_size < SRS_AV_BASE64_SIZE(in_size)) - return NULL; - ret = dst = out; - while (bytes_remaining > 3) { - i_bits = AV_RB32(in); - in += 3; bytes_remaining -= 3; - *dst++ = b64[ i_bits>>26 ]; - *dst++ = b64[(i_bits>>20) & 0x3F]; - *dst++ = b64[(i_bits>>14) & 0x3F]; - *dst++ = b64[(i_bits>>8 ) & 0x3F]; + // skip over newlines + for (; si < cipher.length() && (cipher.at(si) == '\n' || cipher.at(si) == '\r'); si++) { } - i_bits = 0; - while (bytes_remaining) { - i_bits = (i_bits << 8) + *in++; - bytes_remaining--; - i_shift += 8; - } - while (i_shift > 0) { - *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; - i_shift -= 6; - } - while ((dst - ret) & 3) - *dst++ = '='; - *dst = '\0'; - return ret; + for (bool end = false; si < cipher.length() && !end;) { + // Decode quantum using the base64 alphabet + uint8_t dbuf[4]; + memset(dbuf, 0x00, sizeof(dbuf)); + + int dinc = 3; + int dlen = 4; + + for (int j = 0; j < sizeof(dbuf); j++) { + if (si == cipher.length()) { + if (padding != -1 || j < 2) { + return srs_error_new(ERROR_BASE64_DECODE, "corrupt input at %d", si); + } + + dinc = j - 1; + dlen = j; + end = true; + break; + } + + char in = cipher.at(si); + + si++; + // skip over newlines + for (; si < cipher.length() && (cipher.at(si) == '\n' || cipher.at(si) == '\r'); si++) { + } + + if (in == padding) { + // We've reached the end and there's padding + switch (j) { + case 0: + case 1: + // incorrect padding + return srs_error_new(ERROR_BASE64_DECODE, "corrupt input at %d", si); + case 2: + // "==" is expected, the first "=" is already consumed. + if (si == cipher.length()) { + return srs_error_new(ERROR_BASE64_DECODE, "corrupt input at %d", si); + } + if (cipher.at(si) != padding) { + // incorrect padding + return srs_error_new(ERROR_BASE64_DECODE, "corrupt input at %d", si); + } + + si++; + // skip over newlines + for (; si < cipher.length() && (cipher.at(si) == '\n' || cipher.at(si) == '\r'); si++) { + } + } + + if (si < cipher.length()) { + // trailing garbage + err = srs_error_new(ERROR_BASE64_DECODE, "corrupt input at %d", si); + } + dinc = 3; + dlen = j; + end = true; + break; + } + + dbuf[j] = decodeMap[(uint8_t)in]; + if (dbuf[j] == 0xff) { + return srs_error_new(ERROR_BASE64_DECODE, "corrupt input at %d", si); + } + } + + // Convert 4x 6bit source bytes into 3 bytes + uint32_t val = uint32_t(dbuf[0])<<18 | uint32_t(dbuf[1])<<12 | uint32_t(dbuf[2])<<6 | uint32_t(dbuf[3]); + if (dlen >= 2) { + plaintext.append(1, char(val >> 16)); + } + if (dlen >= 3) { + plaintext.append(1, char(val >> 8)); + } + if (dlen >= 4) { + plaintext.append(1, char(val)); + } + } + + return err; } #define SPACE_CHARS " \t\r\n" diff --git a/trunk/src/kernel/srs_kernel_utility.hpp b/trunk/src/kernel/srs_kernel_utility.hpp index b0c4665dc..34b63eaca 100644 --- a/trunk/src/kernel/srs_kernel_utility.hpp +++ b/trunk/src/kernel/srs_kernel_utility.hpp @@ -147,27 +147,8 @@ extern uint32_t srs_crc32_ieee(const void* buf, int size, uint32_t previous = 0) /** * Decode a base64-encoded string. - * - * @param out buffer for decoded data - * @param in null-terminated input string - * @param out_size size in bytes of the out buffer, must be at - * least 3/4 of the length of in - * @return number of bytes written, or a negative value in case of - * invalid input */ -extern int srs_av_base64_decode(uint8_t* out, const char* in, int out_size); - -/** - * Encode data to base64 and null-terminate. - * - * @param out buffer for encoded data - * @param out_size size in bytes of the out buffer (including the - * null terminator), must be at least AV_BASE64_SIZE(in_size) - * @param in input buffer containing the data to encode - * @param in_size size in bytes of the in buffer - * @return out or NULL in case of error - */ -extern char* srs_av_base64_encode(char* out, int out_size, const uint8_t* in, int in_size); +extern srs_error_t srs_av_base64_decode(std::string cipher, std::string& plaintext); /** * Calculate the output size needed to base64-encode x bytes to a diff --git a/trunk/src/protocol/srs_rtsp_stack.cpp b/trunk/src/protocol/srs_rtsp_stack.cpp index f20daa014..55a306c7f 100644 --- a/trunk/src/protocol/srs_rtsp_stack.cpp +++ b/trunk/src/protocol/srs_rtsp_stack.cpp @@ -583,23 +583,16 @@ srs_error_t SrsRtspSdp::parse_control_attribute(string attr) return err; } -string SrsRtspSdp::base64_decode(string value) +string SrsRtspSdp::base64_decode(string cipher) { - if (value.empty()) { + if (cipher.empty()) { return ""; } - int nb_output = (int)(value.length() * 2); - uint8_t* output = new uint8_t[nb_output]; - SrsAutoFreeA(uint8_t, output); + string plaintext; + srs_error_t err = srs_av_base64_decode(cipher, plaintext); + srs_freep(err); - int ret = srs_av_base64_decode(output, (char*)value.c_str(), nb_output); - if (ret <= 0) { - return ""; - } - - std::string plaintext; - plaintext.append((char*)output, ret); return plaintext; } diff --git a/trunk/src/utest/srs_utest_kernel.cpp b/trunk/src/utest/srs_utest_kernel.cpp index 5fafd417f..4b6364e1f 100644 --- a/trunk/src/utest/srs_utest_kernel.cpp +++ b/trunk/src/utest/srs_utest_kernel.cpp @@ -1674,5 +1674,15 @@ VOID TEST(KernelUtility, CRC32MPEGTS) } } +VOID TEST(KernelUtility, Base64Decode) +{ + string cipher = "dXNlcjpwYXNzd29yZA=="; + string expect = "user:password"; + + string plaintext; + EXPECT_TRUE(srs_success == srs_av_base64_decode(cipher, plaintext)); + EXPECT_TRUE(expect == plaintext); +} + #endif