#include <iostream>
#include <cstdint>
#include <string>
#include <vector>
#include <algorithm>
#include <bitset>
// https://github.com/zaphoyd/websocketpp/blob/master/websocketpp/base64/base64.hpp
#include "base64.hpp"
uint8_t decode_base36(uint8_t c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'z') {
return c - 'a' + 10;
}
return 0xff;
}
template<typename ItBegin, typename ItEnd>
inline void decrypt_spade_inner(ItBegin spade_key, ItEnd spade_key_end) {
std::vector<uint8_t> buff(spade_key_end - spade_key + 2);
buff[0] = 0xFA;
buff[1] = 0x55;
std::copy(spade_key, spade_key_end, buff.begin() + 2);
const uint8_t* p_table = buff.data();
for (uint32_t i = 0; spade_key < spade_key_end; spade_key++) {
auto pop_count = static_cast<uint8_t>(std::bitset<32>(i).count()); // popcnt 指令
*spade_key = (*spade_key ^ *p_table) - pop_count - 21;
p_table++;
i++;
}
}
template<typename ItBegin, typename ItEnd>
std::string decrypt_spade(ItBegin spade_key, ItEnd spade_key_end) {
size_t spade_key_len = spade_key_end - spade_key;
if (spade_key_len < 3) {
return {};
}
uint8_t padding_len = (spade_key[0] ^ spade_key[1] ^ spade_key[2]) - '0';
if (spade_key_len < static_cast<size_t>(padding_len) + 2) {
return {}; // overflow
}
size_t decoded_message_len = spade_key_len - padding_len - 2;
std::vector<uint8_t> tmp_buff(&spade_key[1], &spade_key[spade_key_len - padding_len]);
decrypt_spade_inner(tmp_buff.begin(), tmp_buff.end());
auto skip_bytes = decode_base36(tmp_buff[0]);
return std::string(&tmp_buff[1], &tmp_buff[1 + decoded_message_len - skip_bytes]);
}
std::string decrypt_spade_a(std::string const& spade_a) {
auto spade = websocketpp::base64_decode(spade_a); // base64 解码
return decrypt_spade(spade.cbegin(), spade.cend());
}
int main()
{
// uint8_t szInput[] = { 0x90, 0xbc, 0x1e, 0xfa, 0x56, 0xbd, 0x06, 0xf6, 0x4b, 0xbf, 0x0c, 0xef, 0x71, 0xa2, 0x3d, 0xec, 0x73, 0xa7, 0x3c, 0xef, 0x42, 0x94, 0x0a, 0xe8, 0x45, 0xb8, 0x0a, 0xf1, 0x76, 0xb9, 0x08, 0xf0, 0x42, 0xb8, 0x0a, 0x83, 0x83 };
// std::string key = decrypt_spade(szInput, szInput+sizeof(szInput));
auto key = decrypt_spade_a("kLwe+la9BvZLvwzvcaI97HOnPO9ClAroRbgK8Xa5CPBCuAqDgw==");
auto key_ok = key == "5011945309e6465581fd0d6971c0e002";
std::cout << key << " -- " << (key_ok ? "OK" : "BAD") << std::endl;
}