diff --git a/src/bridge/BridgeConnection.cpp b/src/bridge/BridgeConnection.cpp index f2a1ef6..aa520cf 100644 --- a/src/bridge/BridgeConnection.cpp +++ b/src/bridge/BridgeConnection.cpp @@ -110,6 +110,7 @@ void BridgeConnection::InjectMessage(QString msg){ //Add the "from" ID to the message msg = msg.replace(0,lb,SockID); //replace the "to" ID with the "from" ID emit SocketMessage(toID, msg); //forward the message on to the "to" connection + //qDebug() << "Message:" << toID << SockID << msg; //simple message snooping on the bridge - to verify server/client encryption } } } diff --git a/src/server/AuthorizationManager.cpp b/src/server/AuthorizationManager.cpp index 1e402ea..6bc069d 100644 --- a/src/server/AuthorizationManager.cpp +++ b/src/server/AuthorizationManager.cpp @@ -338,13 +338,143 @@ QString AuthorizationManager::LoginUC(QHostAddress host, QString encstring){ } } -QString AuthorizationManager::encryptString(QString msg, QString key){ - //do nothing yet - return msg; +QString AuthorizationManager::encryptString(QString str, QByteArray key){ + return str; //TEMPORARY BYPASS + bool pub=true; + if(key.contains("--BEGIN PUBLIC KEY--")){ pub=true; } + else if(key.contains(" PRIVATE KEY--")){ pub=false; } + else{ return str; } //unknown encryption - just return as-is + qDebug() << "Encrypt String:" << str << pub;//<< key; + //Reset/Load some SSL stuff + //OpenSSL_add_all_algorithms(); + //ERR_load_crypto_strings(); + + //Now Encrypt the string + //qDebug() << "allocate encode array"; + unsigned char *encode = (unsigned char*)malloc(2*str.length()); //give it plenty of extra space as needed + RSA *rsa= NULL; + BIO *keybio = NULL; + //qDebug() << "allocate keybio buffer"; + keybio = BIO_new_mem_buf(key.data(), -1); + if(keybio==NULL){ return ""; } + + if(!pub){ + //Using PRIVATE key to encrypt + //qDebug() << "Read private key"; + rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL); + if(rsa==NULL){ return ""; } + //qDebug() << "Encrypt with private key"; + int len = RSA_private_encrypt(str.length(), (unsigned char*)(str.toLocal8Bit().data()), encode, rsa, RSA_PKCS1_PADDING); + if(len <0){ return ""; } + //qDebug() << "Return base-64 encoded version"; + QByteArray str_encode( (char*)(encode), len); + str_encode = str_encode.toBase64(); + return QString( str_encode ); + }else{ + //Using PUBLIC key to encrypt + //qDebug() << "Read Public Key"; + rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); + if(rsa==NULL){ return ""; } + //qDebug() << "Encrypt with public key"; + int len = RSA_public_encrypt(str.length(), (unsigned char*)(str.toLocal8Bit().data()), encode, rsa, RSA_PKCS1_PADDING); + if(len <0){ return ""; } + //qDebug() << "Return base-64 encoded version"; + QByteArray str_encode = QByteArray::fromRawData( (char*)(encode), len); + qDebug() << "Encoded:" << str_encode; + str_encode = str_encode.toBase64(); + qDebug() << "Could reverse encoding:" << (decryptString(str_encode, key) == str); + qDebug() << "Base64:" << str_encode; + + return QString( str_encode ); + } + return str; } -QString AuthorizationManager::decryptString(QString msg, QString key){ - return msg; //do nothing yet +QString AuthorizationManager::decryptString(QString str, QByteArray key){ + return str; //TEMPORARY BYPASS + bool pub=true; + if(key.contains("--BEGIN PUBLIC KEY--")){ pub=true; } + else if(key.contains(" PRIVATE KEY--")){ pub=false; } + else{ return str; } //unknown encryption - just return as-is + //Reset/Load some SSL stuff + // OpenSSL_add_all_algorithms(); + // ERR_load_crypto_strings(); + + //Turn the encrypted string into a byte array + QByteArray enc; enc.append(str.toLocal8Bit()); + + unsigned char *decode = (unsigned char*)malloc(2*str.length()); + RSA *rsa= NULL; + BIO *keybio = NULL; + //qDebug() << " - Generate keybio"; + keybio = BIO_new_mem_buf(key.data(), -1); + if(keybio==NULL){ return ""; } + //qDebug() << " - Read pubkey"; + if(pub){ + //PUBLIC KEY + rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); + if(rsa==NULL){ qDebug() << " - Invalid RSA key!!"; return ""; } + //qDebug() << " - Decrypt string"; + int len = RSA_public_decrypt(enc.length(), (unsigned char*)(enc.data()), decode, rsa, RSA_PKCS1_PADDING); + if(len<0){ return ""; } + return QString( QByteArray( (char*)(decode), len) ); + }else{ + //PRIVATE KEY + rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL); + if(rsa==NULL){ qDebug() << " - Invalid RSA key!!"; return ""; } + //qDebug() << " - Decrypt string"; + int len = RSA_private_decrypt(enc.length(), (unsigned char*)(enc.data()), decode, rsa, RSA_PKCS1_PADDING); + if(len<0){ return ""; } + return QString( QByteArray( (char*)(decode), len) ); + } +} + +//Additional SSL Encryption functions +QByteArray AuthorizationManager::GenerateSSLPrivkey(){ + const int kBits = 4096; //25165824; // 3MB in bits + const int kExp = 3; + + int keylen; + char *pem_key; + + RSA *rsa = RSA_generate_key(kBits, kExp, 0, 0); + + /* To get the C-string PEM form: */ + BIO *bio = BIO_new(BIO_s_mem()); + PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL); + + keylen = BIO_pending(bio); + pem_key = (char *)malloc(keylen+1); /* Null-terminate */ + BIO_read(bio, pem_key, keylen); + QByteArray data = QByteArray::fromRawData(pem_key, keylen); + qDebug() << "New Priv Key:" << data; + return data; +} + +QByteArray AuthorizationManager::pubkeyForMd5(QString md5_base64){ + QByteArray md5 = QByteArray::fromBase64( md5_base64.toLocal8Bit() ); + +QStringList keys; //Format: "RegisteredCerts//" (value is full text) + //Read all user's certs (since we only need checksums) + keys = CONFIG->allKeys().filter("RegisteredCerts/"); + keys.sort(); + QJsonArray arr; + QCryptographicHash chash(QCryptographicHash::Md5); + //qDebug() << "MD5 Generation:"; + for(int i=0; i HASH; QHash IPFAIL; diff --git a/src/server/WebServer.cpp b/src/server/WebServer.cpp index 37a8fa0..ddaf6d4 100644 --- a/src/server/WebServer.cpp +++ b/src/server/WebServer.cpp @@ -40,7 +40,7 @@ bool WebServer::startServer(quint16 port, bool websocket){ if(ok){ QCoreApplication::processEvents(); qDebug() << "Server Started:" << QDateTime::currentDateTime().toString(Qt::ISODate); - qDebug() << " Port:" << port; + qDebug() << " Port:" << (BRIDGE_ONLY ? "(Bridge Only)" : QString::number(port)); if(WSServer!=0){ qDebug() << " URL:" << WSServer->serverUrl().toString(); } }else{ qCritical() << "Could not start server - exiting..."; diff --git a/src/server/WebSocket.cpp b/src/server/WebSocket.cpp index f8ba576..be2701c 100644 --- a/src/server/WebSocket.cpp +++ b/src/server/WebSocket.cpp @@ -76,7 +76,7 @@ WebSocket::WebSocket(QObject *parent, QString url, QString ID, AuthorizationMana TSOCKET = 0; AUTHSYSTEM = auth; SockPeerIP = SOCKET->peerAddress().toString(); - LogManager::log(LogManager::HOST,"New Connection: "+SockPeerIP); + //LogManager::log(LogManager::HOST,"New Bridge Connection: "+SockPeerIP); idletimer = new QTimer(this); idletimer->setInterval(IDLETIMEOUTMINS*60000); //connection timout for idle sockets idletimer->setSingleShot(true); @@ -254,19 +254,40 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){ }else if(out.in_struct.name=="auth_ssl"){ if(out.in_struct.args.isObject() && out.in_struct.args.toObject().contains("encrypted_string")){ //Stage 2: Check the returned encrypted/string + qDebug() << "State 2 SSL Auth Request"; cur_auth_tok = AUTHSYSTEM->LoginUC(host, JsonValueToString(out.in_struct.args.toObject().value("encrypted_string")) ); }else{ //Stage 1: Send the client a random string to encrypt with their SSL key QString key = AUTHSYSTEM->GenerateEncCheckString(); - QJsonObject obj; obj.insert("test_string", key); + QJsonObject obj; + /*if(out.in_struct.args.toObject().contains("md5_key")){ + qDebug() << "Encrypted SSL Auth Requested"; + QString md5 = out.in_struct.args.toObject().value("md5_key").toString(); //Note: This is base64 encoded right now + //qDebug() << " - Get pub key for md5"; + QByteArray pubkey = AUTHSYSTEM->pubkeyForMd5(md5); + //qDebug() << " - Generate new Priv key"; + QByteArray privkey = AUTHSYSTEM->GenerateSSLPrivkey(); + //Now break up the private key into 128 byte chunks and encrypt with public key for transport + //qDebug() << " - Destruct priv key into chunks" << "Length:" << privkey.size(); + QJsonArray pkeyarr; + for(int i=0; iencryptString( QString(privkey.mid(i,64)), pubkey); + } + obj.insert("new_ssl_key", pkeyarr); //send this to the client for re-assembly + //Also encrypt the test string with the public key as well + //qDebug() << " - Encrypt test string with pubkey"; + key = AUTHSYSTEM->encryptString( key, pubkey); + //qDebug() << " - Done with special SSL section"; + BRIDGE[REQ.bridgeID].enc_key = privkey; + }*/ + obj.insert("test_string", key); out.out_args = obj; out.CODE = RestOutputStruct::OK; QString msg = out.assembleMessage(); if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){ - //BRIDGE RELAY - alternate format - //Need to encrypt the message for output (TO-DO) - QString key = BRIDGE[REQ.bridgeID].enc_key; - if(!key.isEmpty()){ msg = AUTHSYSTEM->encryptString(msg, key); } + //BRIDGE RELAY - alternate format + //Note that the Stage 1 SSL auth reply is only partially encrypted (specific variables only, not bulk message encryption) //Now add the destination ID msg.prepend( REQ.bridgeID+"\n"); } @@ -383,12 +404,10 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){ //Return any information QString msg = out.assembleMessage(); if(SOCKET!=0 && !REQ.bridgeID.isEmpty()){ - //BRIDGE RELAY - alternate format - //Need to encrypt the message for output (TO-DO) - QString key = BRIDGE[REQ.bridgeID].enc_key; - if(!key.isEmpty()){ msg = AUTHSYSTEM->encryptString(msg, key); } - //Now add the destination ID - msg.prepend( REQ.bridgeID+"\n"); + //BRIDGE RELAY - alternate format + msg = AUTHSYSTEM->encryptString(msg, BRIDGE[REQ.bridgeID].enc_key); + //Now add the destination ID + msg.prepend( REQ.bridgeID+"\n"); } if(out.CODE == RestOutputStruct::FORBIDDEN && SOCKET!=0 && SOCKET->isValid()){ this->sendReply(msg); @@ -521,7 +540,7 @@ void WebSocket::EvaluateMessage(const QByteArray &msg){ } void WebSocket::EvaluateMessage(const QString &msg){ - //qDebug() << "New Text Message:"; + qDebug() << "New Text Message:" << msg; if(idletimer->isActive()){ idletimer->stop(); } idletimer->start(); EvaluateREST(msg); @@ -606,6 +625,8 @@ void WebSocket::SslError(const QList &err){ //sslErrors() signal } void WebSocket::startBridgeAuth(){ + SockPeerIP = SOCKET->peerAddress().toString(); + LogManager::log(LogManager::HOST,"New Bridge Connection: "+SockPeerIP); //qDebug() << "Init Bridge Auth..."; QJsonObject obj; obj.insert("id", "server_to_bridge_auth"); @@ -637,9 +658,7 @@ void WebSocket::EventUpdate(EventWatcher::EVENT_TYPE evtype, QJsonValue msg){ for(int i=0; iencryptString(raw, key); } + QString enc_data = AUTHSYSTEM->encryptString(raw, BRIDGE[conns[i]].enc_key); //Now add the destination ID enc_data.prepend( conns[i]+"\n"); this->emit SendMessage(enc_data); diff --git a/src/server/WebSocket.h b/src/server/WebSocket.h index 1143edc..de3bc48 100644 --- a/src/server/WebSocket.h +++ b/src/server/WebSocket.h @@ -12,7 +12,8 @@ #include "AuthorizationManager.h" struct bridge_data{ - QString enc_key, auth_tok; + QByteArray enc_key; + QString auth_tok; QList sendEvents; };