218 lines
6.5 KiB
C++
218 lines
6.5 KiB
C++
//
|
|
// Created by wolverindev on 07.10.17.
|
|
//
|
|
|
|
#include <iostream>
|
|
#include <openssl/sha.h>
|
|
#include "misc/base64.h"
|
|
#include "Identity.h"
|
|
|
|
#define ECC_TYPE_INDEX 5
|
|
|
|
using namespace std;
|
|
|
|
static const char *TSKEY =
|
|
"b9dfaa7bee6ac57ac7b65f1094a1c155"
|
|
"e747327bc2fe5d51c512023fe54a2802"
|
|
"01004e90ad1daaae1075d53b7d571c30"
|
|
"e063b5a62a4a017bb394833aa0983e6e";
|
|
|
|
static int obfuscateInplace(char *data, uint32_t length) {
|
|
int dataSize = min((uint32_t) 100, length);
|
|
for (int i = 0; i < dataSize; i++) {
|
|
data[i] ^= TSKEY[i];
|
|
}
|
|
|
|
char hash[20];
|
|
hash_state ctx;
|
|
if (sha1_init(&ctx) != CRYPT_OK)
|
|
{ return -1; }
|
|
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
|
|
{ return -1; }
|
|
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
|
|
{ return -1; }
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
data[i] ^= hash[i];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int deObfuscateInplace(char *data, uint32_t length) {
|
|
char hash[20];
|
|
hash_state ctx;
|
|
if (sha1_init(&ctx) != CRYPT_OK)
|
|
{ return -1; }
|
|
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
|
|
{ return -1; }
|
|
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
|
|
{ return -1; }
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
data[i] ^= hash[i];
|
|
}
|
|
|
|
int dataSize = min((uint32_t) 100, length);
|
|
for (int i = 0; i < dataSize; i++) {
|
|
data[i] ^= TSKEY[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
namespace ts {
|
|
Identity* Identity::createNew() {
|
|
auto result = new Identity();
|
|
|
|
prng_state rndState{};
|
|
memset(&rndState, 0, sizeof(prng_state));
|
|
int err;
|
|
|
|
result->keyPair = new ecc_key;
|
|
|
|
cout << " -> " << find_prng("sprng") << endl;
|
|
if((err = ecc_make_key_ex(&rndState, find_prng("sprng"), result->keyPair, <c_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK) {
|
|
cerr << "Cant create a new identity (Keygen)" << endl;
|
|
cerr << "Message: " << error_to_string(err) << endl;
|
|
delete result;
|
|
return nullptr;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Identity::Identity(std::string asnStruct, int64_t keyOffset, int64_t lastCheckedOffset) {
|
|
this->keyOffset = keyOffset;
|
|
this->lastCheckedOffset = lastCheckedOffset;
|
|
importKey(asnStruct);
|
|
}
|
|
|
|
Identity::Identity(std::string data) : Identity() {
|
|
int vindex = data.find('V');
|
|
assert(vindex > 0);
|
|
|
|
auto slevel = data.substr(0, vindex);
|
|
assert(slevel.find_first_not_of("0123456789") == std::string::npos);
|
|
this->keyOffset = stol(slevel);
|
|
|
|
data = data.substr(vindex + 1);
|
|
data = base64::decode(data);
|
|
if(deObfuscateInplace((char *) data.data(), data.length()) < 0) {
|
|
cerr << "Cand decript identitry data" << endl;
|
|
return;
|
|
}
|
|
importKey(base64::decode(data));
|
|
}
|
|
|
|
Identity::Identity() {
|
|
this->keyOffset = 0;
|
|
this->lastCheckedOffset = 0;
|
|
this->keyPair = nullptr;
|
|
}
|
|
|
|
Identity::~Identity() {
|
|
delete this->keyPair;
|
|
this->keyPair = nullptr;
|
|
}
|
|
|
|
void Identity::importKey(std::string asnStruct) {
|
|
this->keyPair = new ecc_key;
|
|
int err;
|
|
if((err = ecc_import_ex((const unsigned char *) asnStruct.data(), asnStruct.length(), this->keyPair, <c_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK){
|
|
delete this->keyPair;
|
|
this->keyPair = nullptr;
|
|
|
|
cerr << "Cant import identity from asn structure" << endl;
|
|
cerr << "Message: " << error_to_string(err) << endl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::string Identity::exportIdentity() {
|
|
string data = privateKey();
|
|
obfuscateInplace((char *) data.data(), data.length());
|
|
return to_string(this->lastValidKeyOffset()) + "V" + base64_encode(data);
|
|
}
|
|
|
|
std::string Identity::publicKey() {
|
|
assert(this->keyPair);
|
|
|
|
size_t bufferLength = 1028;
|
|
char buffer[bufferLength];
|
|
ecc_export((unsigned char *) buffer, &bufferLength, PK_PUBLIC, this->keyPair);
|
|
|
|
return base64_encode(string(buffer, bufferLength));
|
|
}
|
|
|
|
std::string Identity::privateKey() {
|
|
assert(this->keyPair);
|
|
|
|
size_t bufferLength = 1028;
|
|
char buffer[bufferLength];
|
|
ecc_export((unsigned char *) buffer, &bufferLength, PK_PRIVATE, this->keyPair);
|
|
|
|
return base64_encode(string(buffer, bufferLength));
|
|
}
|
|
|
|
ecc_key& Identity::getPrivateKey() {
|
|
return *keyPair;
|
|
}
|
|
|
|
#define MaxUlongString 20
|
|
|
|
bool Identity::improveSecurityLevel(int target) {
|
|
auto publicKey = this->publicKey();
|
|
char hashBuffer[publicKey.length() + MaxUlongString];
|
|
memcpy(hashBuffer, publicKey.data(), publicKey.length());
|
|
|
|
this->lastCheckedOffset = max(this->lastCheckedOffset, this->keyOffset);
|
|
int best = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
|
|
while(true){
|
|
if(best >= target) return true;
|
|
|
|
int currentLevel = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
|
|
if(currentLevel >= best){
|
|
this->keyOffset = this->lastCheckedOffset;
|
|
best = currentLevel;
|
|
}
|
|
this->lastCheckedOffset++;
|
|
}
|
|
}
|
|
|
|
int Identity::getSecurityLevel() {
|
|
auto length = publicKey().length();
|
|
char hashBuffer[length + MaxUlongString];
|
|
|
|
auto publicKey = this->publicKey();
|
|
memcpy(hashBuffer, publicKey.data(), publicKey.length());
|
|
|
|
return getSecurityLevel(hashBuffer, publicKey.length(), this->keyOffset);
|
|
}
|
|
|
|
int Identity::getSecurityLevel(char *hashBuffer, size_t keyLength, int64_t offset) {
|
|
char numBuffer[MaxUlongString];
|
|
int numLen = 0;
|
|
do {
|
|
numBuffer[numLen] = '0' + (offset % 10);
|
|
offset /= 10;
|
|
numLen++;
|
|
} while(offset > 0);
|
|
for(int i = 0; i < numLen; i++)
|
|
hashBuffer[keyLength + i] = numBuffer[numLen - (i + 1)];
|
|
|
|
char shaBuffer[SHA_DIGEST_LENGTH];
|
|
SHA1((const unsigned char *) hashBuffer, keyLength + numLen, (unsigned char *) shaBuffer);
|
|
|
|
//Leading zero bits
|
|
register int zeroBits = 0;
|
|
register int i;
|
|
for(i = 0; i < SHA_DIGEST_LENGTH; i++)
|
|
if(shaBuffer[i] == 0) zeroBits += 8;
|
|
else break;
|
|
if(i < SHA_DIGEST_LENGTH)
|
|
for(int bit = 0; bit < 8; bit++)
|
|
if((shaBuffer[i] & (1 << bit)) == 0) zeroBits++;
|
|
else break;
|
|
return zeroBits;
|
|
}
|
|
} |