std::vector<uint8_t> kugou_v4_final_key_expansion(const char* table, std::vector<uint8_t> key) {
auto table_len = strlen(table);
auto key_md5 = md5(key);
std::vector<uint8_t> vec_md5;
std::vector<int> indexes = {
5, 14, 13, 2, 12, 10, 15, 11, 3, 8,
5, 6, 9, 4, 3, 7, 0, 14, 13, 6, 2,
12, 10, 15, 1, 11, 8, 7, 9, 4, 1
};
for (auto index : indexes ) {
vec_md5.push_back(key_md5[index]);
}
std::vector<uint8_t> vec_result;
vec_result.reserve((vec_md5_len - 1) * (table_len - 1) * 4);
for (int i = 1; i < vec_md5_len; i++) {
for (int j = 1; j < table_len; j++) {
uint32_t temp = i * j * table[j] * vec_md5[i];
vec_result.push_back(uint8_t(temp));
vec_result.push_back(uint8_t(temp >> 0x18));
vec_result.push_back(uint8_t(temp >> 0x10));
vec_result.push_back(uint8_t(temp >> 0x08));
}
}
return vec_result;
}
// FileKeyExpansion:
static char table_kugou_v4_filekey_expansion[] = "... this is a secret ...";
this->key2 = kugou_v4_final_key_expansion(table_kugou_v4_filekey_expansion, file_key);
// KeySlotKeyExpansion:
static char table_kugou_v4_slotkey_expansion[] = "... this is a secret ...";
key = base64(hex(md5(table_kugou_v4_slotkey_expansion)));
this->key1= kugou_v4_final_key_expansion(table_kugou_v4_slotkey, key);
// decryption:
for (int i = 0; i < n; i++) {
auto key1_index = offset % key1.len();
auto key1_div = offset / key1.len();
auto key2_index = offset % key2.len();
uint8_t temp = buffer[i];
temp ^= key2[key1_div % key2.len()];
temp ^= (temp << 4);
temp ^= key1[key1_index];
temp ^= uint8_t(offset ^ (offset >> 16) ^ (offset >> 8) ^ (offset >> 24));
buffer[i] = temp;
offset++;
}