2017-05-11 05:21:04 +02:00
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <string>
|
2017-05-11 13:20:47 +02:00
|
|
|
|
#include <collection.h>
|
2017-05-11 05:21:04 +02:00
|
|
|
|
#include "CXWrapper.h"
|
|
|
|
|
|
|
|
|
|
using namespace libtgvoip;
|
|
|
|
|
using namespace Platform;
|
|
|
|
|
using namespace tgvoip;
|
|
|
|
|
using namespace Windows::Security::Cryptography;
|
|
|
|
|
using namespace Windows::Security::Cryptography::Core;
|
|
|
|
|
using namespace Windows::Storage::Streams;
|
2017-05-11 13:20:47 +02:00
|
|
|
|
using namespace Windows::Data::Json;
|
2017-05-11 05:21:04 +02:00
|
|
|
|
|
|
|
|
|
//CryptographicHash^ MicrosoftCryptoImpl::sha1Hash;
|
|
|
|
|
//CryptographicHash^ MicrosoftCryptoImpl::sha256Hash;
|
|
|
|
|
HashAlgorithmProvider^ MicrosoftCryptoImpl::sha1Provider;
|
|
|
|
|
HashAlgorithmProvider^ MicrosoftCryptoImpl::sha256Provider;
|
|
|
|
|
SymmetricKeyAlgorithmProvider^ MicrosoftCryptoImpl::aesKeyProvider;
|
|
|
|
|
|
2017-05-11 13:20:47 +02:00
|
|
|
|
/*struct tgvoip_cx_data{
|
2017-05-11 05:21:04 +02:00
|
|
|
|
VoIPControllerWrapper^ self;
|
2017-05-11 13:20:47 +02:00
|
|
|
|
};*/
|
2017-05-11 05:21:04 +02:00
|
|
|
|
|
|
|
|
|
VoIPControllerWrapper::VoIPControllerWrapper(){
|
|
|
|
|
VoIPController::crypto.aes_ige_decrypt=MicrosoftCryptoImpl::AesIgeDecrypt;
|
|
|
|
|
VoIPController::crypto.aes_ige_encrypt=MicrosoftCryptoImpl::AesIgeEncrypt;
|
|
|
|
|
VoIPController::crypto.sha1=MicrosoftCryptoImpl::SHA1;
|
|
|
|
|
VoIPController::crypto.sha256=MicrosoftCryptoImpl::SHA256;
|
|
|
|
|
VoIPController::crypto.rand_bytes=MicrosoftCryptoImpl::RandBytes;
|
2017-05-11 13:20:47 +02:00
|
|
|
|
MicrosoftCryptoImpl::Init();
|
2017-05-11 05:21:04 +02:00
|
|
|
|
controller=new VoIPController();
|
2017-05-11 13:20:47 +02:00
|
|
|
|
controller->implData=(void*)this;
|
2017-05-11 05:21:04 +02:00
|
|
|
|
controller->SetStateCallback(VoIPControllerWrapper::OnStateChanged);
|
|
|
|
|
stateCallback=nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VoIPControllerWrapper::~VoIPControllerWrapper(){
|
|
|
|
|
delete controller;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::Start(){
|
|
|
|
|
controller->Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::Connect(){
|
|
|
|
|
controller->Connect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::SetPublicEndpoints(Windows::Foundation::Collections::IIterable<libtgvoip::Endpoint^>^ endpoints, bool allowP2P){
|
|
|
|
|
Windows::Foundation::Collections::IIterator<libtgvoip::Endpoint^>^ iterator=endpoints->First();
|
|
|
|
|
std::vector<tgvoip::Endpoint> eps;
|
|
|
|
|
while(iterator->HasCurrent){
|
|
|
|
|
libtgvoip::Endpoint^ _ep=iterator->Current;
|
|
|
|
|
tgvoip::Endpoint ep;
|
|
|
|
|
ep.id=_ep->id;
|
|
|
|
|
ep.type=EP_TYPE_UDP_RELAY;
|
|
|
|
|
char buf[128];
|
|
|
|
|
if(_ep->ipv4){
|
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, _ep->ipv4->Data(), -1, buf, sizeof(buf), NULL, NULL);
|
|
|
|
|
ep.address=IPv4Address(buf);
|
|
|
|
|
}
|
|
|
|
|
if(_ep->ipv6){
|
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, _ep->ipv6->Data(), -1, buf, sizeof(buf), NULL, NULL);
|
|
|
|
|
ep.v6address=IPv6Address(buf);
|
|
|
|
|
}
|
|
|
|
|
ep.port=_ep->port;
|
|
|
|
|
if(_ep->peerTag->Length!=16)
|
|
|
|
|
throw ref new Platform::InvalidArgumentException("Peer tag must be exactly 16 bytes long");
|
|
|
|
|
memcpy(ep.peerTag, _ep->peerTag->Data, 16);
|
|
|
|
|
eps.push_back(ep);
|
2017-05-11 13:20:47 +02:00
|
|
|
|
iterator->MoveNext();
|
2017-05-11 05:21:04 +02:00
|
|
|
|
}
|
|
|
|
|
controller->SetRemoteEndpoints(eps, allowP2P);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-11 13:20:47 +02:00
|
|
|
|
void VoIPControllerWrapper::SetNetworkType(NetworkType type){
|
|
|
|
|
controller->SetNetworkType((int)type);
|
2017-05-11 05:21:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::SetStateCallback(IStateCallback^ callback){
|
|
|
|
|
stateCallback=callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::SetMicMute(bool mute){
|
|
|
|
|
controller->SetMicMute(mute);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::SetEncryptionKey(const Platform::Array<uint8>^ key, bool isOutgoing){
|
|
|
|
|
if(key->Length!=256)
|
|
|
|
|
throw ref new Platform::InvalidArgumentException("Encryption key must be exactly 256 bytes long");
|
|
|
|
|
controller->SetEncryptionKey((char*)key->Data, isOutgoing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Platform::String^ VoIPControllerWrapper::GetDebugString(){
|
|
|
|
|
char abuf[10240];
|
|
|
|
|
controller->GetDebugString(abuf, sizeof(abuf));
|
|
|
|
|
wchar_t wbuf[10240];
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, abuf, -1, wbuf, sizeof(wbuf));
|
|
|
|
|
return ref new Platform::String(wbuf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Platform::String^ VoIPControllerWrapper::GetDebugLog(){
|
|
|
|
|
std::string log=controller->GetDebugLog();
|
|
|
|
|
size_t len=sizeof(wchar_t)*(log.length()+1);
|
|
|
|
|
wchar_t* wlog=(wchar_t*)malloc(len);
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, log.c_str(), -1, wlog, len/sizeof(wchar_t));
|
|
|
|
|
Platform::String^ res=ref new Platform::String(wlog);
|
|
|
|
|
free(wlog);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-11 13:20:47 +02:00
|
|
|
|
Error VoIPControllerWrapper::GetLastError(){
|
|
|
|
|
return (Error)controller->GetLastError();
|
2017-05-11 05:21:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Platform::String^ VoIPControllerWrapper::GetVersion(){
|
|
|
|
|
const char* v=VoIPController::GetVersion();
|
|
|
|
|
wchar_t buf[32];
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, v, -1, buf, sizeof(buf));
|
|
|
|
|
return ref new Platform::String(buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::OnStateChanged(VoIPController* c, int state){
|
2017-05-11 13:20:47 +02:00
|
|
|
|
reinterpret_cast<VoIPControllerWrapper^>(c->implData)->OnStateChangedInternal(state);
|
2017-05-11 05:21:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::OnStateChangedInternal(int state){
|
|
|
|
|
if(stateCallback)
|
2017-05-11 13:20:47 +02:00
|
|
|
|
stateCallback->OnCallStateChanged((CallState)state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::SetConfig(double initTimeout, double recvTimeout, DataSavingMode dataSavingMode, bool enableAEC, bool enableNS, bool enableAGC, Platform::String^ logFilePath, Platform::String^ statsDumpFilePath){
|
|
|
|
|
voip_config_t config{0};
|
|
|
|
|
config.init_timeout=initTimeout;
|
|
|
|
|
config.recv_timeout=recvTimeout;
|
|
|
|
|
config.data_saving=(int)dataSavingMode;
|
|
|
|
|
config.enableAEC=enableAEC;
|
|
|
|
|
config.enableAGC=enableAGC;
|
|
|
|
|
config.enableNS=enableNS;
|
|
|
|
|
if(logFilePath!=nullptr){
|
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, logFilePath->Data(), -1, config.logFilePath, sizeof(config.logFilePath), NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
if(statsDumpFilePath!=nullptr){
|
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, statsDumpFilePath->Data(), -1, config.statsDumpFilePath, sizeof(config.statsDumpFilePath), NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
controller->SetConfig(&config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoIPControllerWrapper::UpdateServerConfig(Platform::String^ json){
|
|
|
|
|
JsonObject^ jconfig=JsonValue::Parse(json)->GetObject();
|
|
|
|
|
std::map<std::string, std::string> config;
|
|
|
|
|
|
|
|
|
|
for each (auto item in jconfig){
|
|
|
|
|
char _key[128];
|
|
|
|
|
char _value[256];
|
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, item->Key->Data(), -1, _key, sizeof(_key), NULL, NULL);
|
2017-05-11 14:05:59 +02:00
|
|
|
|
if(item->Value->ValueType==Windows::Data::Json::JsonValueType::String)
|
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, ((Platform::String^)item->Value)->Data(), -1, _value, sizeof(_value), NULL, NULL);
|
|
|
|
|
else
|
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, item->Value->ToString()->Data(), -1, _value, sizeof(_value), NULL, NULL);
|
2017-05-11 13:20:47 +02:00
|
|
|
|
std::string key(_key);
|
|
|
|
|
std::string value(_value);
|
|
|
|
|
|
|
|
|
|
config[key]=value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ServerConfig::GetSharedInstance()->Update(config);
|
2017-05-11 05:21:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MicrosoftCryptoImpl::AesIgeEncrypt(uint8_t* in, uint8_t* out, size_t len, uint8_t* key, uint8_t* iv){
|
|
|
|
|
Platform::Array<uint8>^ keybuf=ref new Platform::Array<uint8>(16);
|
|
|
|
|
memcpy(keybuf->Data, key, 16);
|
|
|
|
|
CryptographicKey^ _key=aesKeyProvider->CreateSymmetricKey(CryptographicBuffer::CreateFromByteArray(keybuf));
|
|
|
|
|
Platform::Array<uint8>^ tmpIn=ref new Platform::Array<uint8>(16);
|
|
|
|
|
Platform::Array<uint8>^ tmpOut=ref new Platform::Array<uint8>(16);
|
|
|
|
|
uint8_t* xPrev=iv+16;
|
|
|
|
|
uint8_t* yPrev=iv;
|
|
|
|
|
for(size_t offset=0;offset<len;offset+=16){
|
|
|
|
|
uint8_t* y=tmpIn->Data;
|
|
|
|
|
uint8_t* x=in+offset;
|
|
|
|
|
XorInt128(x, yPrev, y);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicEngine::Encrypt(_key, CryptographicBuffer::CreateFromByteArray(tmpIn), nullptr), &tmpOut);
|
|
|
|
|
XorInt128(tmpOut->Data, xPrev, y);
|
|
|
|
|
memcpy(xPrev, x, 16);
|
|
|
|
|
memcpy(yPrev, y, 16);
|
|
|
|
|
memcpy(out+offset, y, 16);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MicrosoftCryptoImpl::AesIgeDecrypt(uint8_t* in, uint8_t* out, size_t len, uint8_t* key, uint8_t* iv){
|
|
|
|
|
Platform::Array<uint8>^ keybuf=ref new Platform::Array<uint8>(16);
|
|
|
|
|
memcpy(keybuf->Data, key, 16);
|
|
|
|
|
CryptographicKey^ _key=aesKeyProvider->CreateSymmetricKey(CryptographicBuffer::CreateFromByteArray(keybuf));
|
|
|
|
|
Platform::Array<uint8>^ tmpIn=ref new Platform::Array<uint8>(16);
|
|
|
|
|
Platform::Array<uint8>^ tmpOut=ref new Platform::Array<uint8>(16);
|
|
|
|
|
uint8_t* xPrev=iv;
|
|
|
|
|
uint8_t* yPrev=iv+16;
|
|
|
|
|
for(size_t offset=0;offset<len;offset+=16){
|
|
|
|
|
uint8_t* y=tmpIn->Data;
|
|
|
|
|
uint8_t* x=in+offset;
|
|
|
|
|
XorInt128(x, yPrev, y);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicEngine::Decrypt(_key, CryptographicBuffer::CreateFromByteArray(tmpIn), nullptr), &tmpOut);
|
|
|
|
|
XorInt128(tmpOut->Data, xPrev, y);
|
|
|
|
|
memcpy(xPrev, x, 16);
|
|
|
|
|
memcpy(yPrev, y, 16);
|
|
|
|
|
memcpy(out+offset, y, 16);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MicrosoftCryptoImpl::SHA1(uint8_t* msg, size_t len, uint8_t* out){
|
|
|
|
|
//EnterCriticalSection(&hashMutex);
|
|
|
|
|
|
|
|
|
|
Platform::Array<uint8>^ arr=ref new Platform::Array<uint8>(len);
|
|
|
|
|
memcpy(arr->Data, msg, len);
|
|
|
|
|
CryptographicHash^ hash=sha1Provider->CreateHash();
|
|
|
|
|
hash->Append(CryptographicBuffer::CreateFromByteArray(arr));
|
|
|
|
|
IBuffer^ res=hash->GetValueAndReset();
|
2017-05-11 14:05:59 +02:00
|
|
|
|
Platform::Array<uint8>^ _out=ref new Platform::Array<uint8>(20);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(res, &_out);
|
|
|
|
|
memcpy(out, _out->Data, 20);
|
2017-05-11 05:21:04 +02:00
|
|
|
|
|
|
|
|
|
//LeaveCriticalSection(&hashMutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MicrosoftCryptoImpl::SHA256(uint8_t* msg, size_t len, uint8_t* out){
|
|
|
|
|
//EnterCriticalSection(&hashMutex);
|
|
|
|
|
|
|
|
|
|
Platform::Array<uint8>^ arr=ref new Platform::Array<uint8>(len);
|
|
|
|
|
memcpy(arr->Data, msg, len);
|
|
|
|
|
CryptographicHash^ hash=sha256Provider->CreateHash();
|
|
|
|
|
hash->Append(CryptographicBuffer::CreateFromByteArray(arr));
|
|
|
|
|
IBuffer^ res=hash->GetValueAndReset();
|
2017-05-11 14:05:59 +02:00
|
|
|
|
Platform::Array<uint8>^ _out=ref new Platform::Array<uint8>(32);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(res, &_out);
|
|
|
|
|
memcpy(out, _out->Data, 32);
|
2017-05-11 05:21:04 +02:00
|
|
|
|
|
|
|
|
|
//LeaveCriticalSection(&hashMutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MicrosoftCryptoImpl::RandBytes(uint8_t* buffer, size_t len){
|
|
|
|
|
Platform::Array<uint8>^ a=ref new Platform::Array<uint8>(len);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::GenerateRandom(len), &a);
|
|
|
|
|
memcpy(buffer, a->Data, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MicrosoftCryptoImpl::Init(){
|
|
|
|
|
/*sha1Hash=HashAlgorithmProvider::OpenAlgorithm(HashAlgorithmNames::Sha1)->CreateHash();
|
|
|
|
|
sha256Hash=HashAlgorithmProvider::OpenAlgorithm(HashAlgorithmNames::Sha256)->CreateHash();*/
|
|
|
|
|
sha1Provider=HashAlgorithmProvider::OpenAlgorithm(HashAlgorithmNames::Sha1);
|
|
|
|
|
sha256Provider=HashAlgorithmProvider::OpenAlgorithm(HashAlgorithmNames::Sha256);
|
|
|
|
|
aesKeyProvider=SymmetricKeyAlgorithmProvider::OpenAlgorithm(SymmetricAlgorithmNames::AesEcb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MicrosoftCryptoImpl::XorInt128(uint8_t* a, uint8_t* b, uint8_t* out){
|
|
|
|
|
uint64_t* _a=reinterpret_cast<uint64_t*>(a);
|
|
|
|
|
uint64_t* _b=reinterpret_cast<uint64_t*>(b);
|
|
|
|
|
uint64_t* _out=reinterpret_cast<uint64_t*>(out);
|
|
|
|
|
_out[0]=_a[0]^_b[0];
|
|
|
|
|
_out[1]=_a[1]^_b[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*Platform::String^ VoIPControllerWrapper::TestAesIge(){
|
|
|
|
|
MicrosoftCryptoImpl::Init();
|
|
|
|
|
Platform::String^ res="";
|
|
|
|
|
Platform::Array<uint8>^ data=ref new Platform::Array<uint8>(32);
|
|
|
|
|
Platform::Array<uint8>^ out=ref new Platform::Array<uint8>(32);
|
|
|
|
|
Platform::Array<uint8>^ key=ref new Platform::Array<uint8>(16);
|
|
|
|
|
Platform::Array<uint8>^ iv=ref new Platform::Array<uint8>(32);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("0000000000000000000000000000000000000000000000000000000000000000"), &data);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), &iv);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("000102030405060708090a0b0c0d0e0f"), &key);
|
|
|
|
|
MicrosoftCryptoImpl::AesIgeEncrypt(data->Data, out->Data, 32, key->Data, iv->Data);
|
|
|
|
|
res+=CryptographicBuffer::EncodeToHexString(CryptographicBuffer::CreateFromByteArray(out));
|
|
|
|
|
res+="\n";
|
|
|
|
|
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("1A8519A6557BE652E9DA8E43DA4EF4453CF456B4CA488AA383C79C98B34797CB"), &data);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), &iv);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("000102030405060708090a0b0c0d0e0f"), &key);
|
|
|
|
|
MicrosoftCryptoImpl::AesIgeDecrypt(data->Data, out->Data, 32, key->Data, iv->Data);
|
|
|
|
|
res+=CryptographicBuffer::EncodeToHexString(CryptographicBuffer::CreateFromByteArray(out));
|
|
|
|
|
res+="\n";
|
|
|
|
|
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("99706487A1CDE613BC6DE0B6F24B1C7AA448C8B9C3403E3467A8CAD89340F53B"), &data);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("6D656E746174696F6E206F6620494745206D6F646520666F72204F70656E5353"), &iv);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("5468697320697320616E20696D706C65"), &key);
|
|
|
|
|
MicrosoftCryptoImpl::AesIgeEncrypt(data->Data, out->Data, 32, key->Data, iv->Data);
|
|
|
|
|
res+=CryptographicBuffer::EncodeToHexString(CryptographicBuffer::CreateFromByteArray(out));
|
|
|
|
|
res+="\n";
|
|
|
|
|
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("4C2E204C6574277320686F70652042656E20676F74206974207269676874210A"), &data);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("6D656E746174696F6E206F6620494745206D6F646520666F72204F70656E5353"), &iv);
|
|
|
|
|
CryptographicBuffer::CopyToByteArray(CryptographicBuffer::DecodeFromHexString("5468697320697320616E20696D706C65"), &key);
|
|
|
|
|
MicrosoftCryptoImpl::AesIgeDecrypt(data->Data, out->Data, 32, key->Data, iv->Data);
|
|
|
|
|
res+=CryptographicBuffer::EncodeToHexString(CryptographicBuffer::CreateFromByteArray(out));
|
|
|
|
|
return res;
|
|
|
|
|
}*/
|