|
@@ -0,0 +1,134 @@
|
|
|
|
|
+#include "usersig.h"
|
|
|
|
|
+
|
|
|
|
|
+#include <stdexcept>
|
|
|
|
|
+#include <ctime>
|
|
|
|
|
+#include <vector>
|
|
|
|
|
+#include <sstream>
|
|
|
|
|
+
|
|
|
|
|
+#include <openssl/hmac.h>
|
|
|
|
|
+#include <openssl/evp.h>
|
|
|
|
|
+#include <zlib.h>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// 简单的 Base64 实现
|
|
|
|
|
+const std::string BASE64_CHARS =
|
|
|
|
|
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
|
+ "abcdefghijklmnopqrstuvwxyz"
|
|
|
|
|
+ "0123456789+/";
|
|
|
|
|
+
|
|
|
|
|
+std::string base64Encode(const unsigned char* data, size_t len) {
|
|
|
|
|
+ std::string ret;
|
|
|
|
|
+ ret.reserve(((len + 2) / 3) * 4);
|
|
|
|
|
+
|
|
|
|
|
+ unsigned int val = 0;
|
|
|
|
|
+ int valb = -6;
|
|
|
|
|
+ for (size_t i = 0; i < len; ++i) {
|
|
|
|
|
+ val = (val << 8) + data[i];
|
|
|
|
|
+ valb += 8;
|
|
|
|
|
+ while (valb >= 0) {
|
|
|
|
|
+ ret.push_back(BASE64_CHARS[(val >> valb) & 0x3F]);
|
|
|
|
|
+ valb -= 6;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (valb > -6) {
|
|
|
|
|
+ ret.push_back(BASE64_CHARS[((val << 8) >> (valb + 8)) & 0x3F]);
|
|
|
|
|
+ }
|
|
|
|
|
+ while (ret.size() % 4) {
|
|
|
|
|
+ ret.push_back('=');
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// '+' -> '*', '/' -> '-', '=' -> '_'
|
|
|
|
|
+std::string base64ToUrlSafe(std::string s) {
|
|
|
|
|
+ for (char& c : s) {
|
|
|
|
|
+ if (c == '+') c = '*';
|
|
|
|
|
+ else if (c == '/') c = '-';
|
|
|
|
|
+ else if (c == '=') c = '_';
|
|
|
|
|
+ }
|
|
|
|
|
+ return s;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 使用 OpenSSL 计算 HMAC-SHA256
|
|
|
|
|
+std::string hmacSHA256(const std::string& key, const std::string& msg) {
|
|
|
|
|
+ unsigned char md[EVP_MAX_MD_SIZE];
|
|
|
|
|
+ unsigned int md_len = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (!HMAC(EVP_sha256(),
|
|
|
|
|
+ key.data(), static_cast<int>(key.size()),
|
|
|
|
|
+ reinterpret_cast<const unsigned char*>(msg.data()),
|
|
|
|
|
+ msg.size(),
|
|
|
|
|
+ md, &md_len)) {
|
|
|
|
|
+ throw std::runtime_error("HMAC(EVP_sha256) 计算失败");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return std::string(reinterpret_cast<char*>(md), md_len);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 使用 zlib 压缩
|
|
|
|
|
+std::string zlibCompress(const std::string& input) {
|
|
|
|
|
+ if (input.empty()) return std::string();
|
|
|
|
|
+
|
|
|
|
|
+ uLong srcLen = static_cast<uLong>(input.size());
|
|
|
|
|
+ uLong destLen = compressBound(srcLen);
|
|
|
|
|
+ std::vector<Bytef> out(destLen);
|
|
|
|
|
+
|
|
|
|
|
+ int ret = compress2(out.data(), &destLen,
|
|
|
|
|
+ reinterpret_cast<const Bytef*>(input.data()),
|
|
|
|
|
+ srcLen, Z_BEST_SPEED);
|
|
|
|
|
+ if (ret != Z_OK) {
|
|
|
|
|
+ throw std::runtime_error("zlib compress2 失败, ret = " + std::to_string(ret));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return std::string(reinterpret_cast<char*>(out.data()), destLen);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+std::string GenerateUserSig(const std::string& user_id,
|
|
|
|
|
+ int sdk_app_id,
|
|
|
|
|
+ const std::string& secret_key,
|
|
|
|
|
+ std::uint32_t expire) {
|
|
|
|
|
+ if (sdk_app_id <= 0) {
|
|
|
|
|
+ throw std::invalid_argument("sdk_app_id 无效");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (secret_key.empty()) {
|
|
|
|
|
+ throw std::invalid_argument("secret_key 不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ std::uint32_t curr_time = static_cast<std::uint32_t>(std::time(nullptr));
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 生成需要 HMAC 的原始字符串
|
|
|
|
|
+ std::ostringstream ss;
|
|
|
|
|
+ ss << "TLS.identifier:" << user_id << "\n"
|
|
|
|
|
+ << "TLS.sdkappid:" << sdk_app_id << "\n"
|
|
|
|
|
+ << "TLS.time:" << curr_time << "\n"
|
|
|
|
|
+ << "TLS.expire:" << expire << "\n";
|
|
|
|
|
+ std::string content_to_sign = ss.str();
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 计算 HMAC-SHA256 并做标准 Base64
|
|
|
|
|
+ std::string hmac_res = hmacSHA256(secret_key, content_to_sign);
|
|
|
|
|
+ std::string sig = base64Encode(
|
|
|
|
|
+ reinterpret_cast<const unsigned char*>(hmac_res.data()),
|
|
|
|
|
+ hmac_res.size());
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 拼接 JSON
|
|
|
|
|
+ std::ostringstream json;
|
|
|
|
|
+ json << "{"
|
|
|
|
|
+ << "\"TLS.ver\":\"2.0\","
|
|
|
|
|
+ << "\"TLS.identifier\":\"" << user_id << "\","
|
|
|
|
|
+ << "\"TLS.sdkappid\":" << sdk_app_id << ","
|
|
|
|
|
+ << "\"TLS.expire\":" << expire << ","
|
|
|
|
|
+ << "\"TLS.time\":" << curr_time << ","
|
|
|
|
|
+ << "\"TLS.sig\":\"" << sig << "\""
|
|
|
|
|
+ << "}";
|
|
|
|
|
+ std::string json_str = json.str();
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 压缩 + Base64 + URL 安全替换
|
|
|
|
|
+ std::string compressed = zlibCompress(json_str);
|
|
|
|
|
+ std::string b64 = base64Encode(
|
|
|
|
|
+ reinterpret_cast<const unsigned char*>(compressed.data()),
|
|
|
|
|
+ compressed.size());
|
|
|
|
|
+ std::string url_safe = base64ToUrlSafe(b64);
|
|
|
|
|
+
|
|
|
|
|
+ return url_safe;
|
|
|
|
|
+}
|