From ea9ed1fa6b8229b1a1a4a793856a3e09cd5006ad Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Fri, 27 May 2016 11:39:12 -0400 Subject: [PATCH] Enable a randomized encryption layer within the server->client communications through a bridge. --- src/server/AuthorizationManager.cpp | 202 +++++++++++++++++++--------- src/server/WebSocket.cpp | 25 ++-- 2 files changed, 150 insertions(+), 77 deletions(-) diff --git a/src/server/AuthorizationManager.cpp b/src/server/AuthorizationManager.cpp index 435b7ee..a64743c 100644 --- a/src/server/AuthorizationManager.cpp +++ b/src/server/AuthorizationManager.cpp @@ -32,7 +32,7 @@ // -- token management #define TIMEOUTSECS 900 // (15 minutes) time before a token becomes invalid #define AUTHCHARS QString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") -#define TOKENLENGTH 40 +#define TOKENLENGTH 20 AuthorizationManager::AuthorizationManager() : QObject(){ HASH.clear(); @@ -341,111 +341,163 @@ QString AuthorizationManager::LoginUC(QHostAddress host, QString encstring){ QString AuthorizationManager::encryptString(QString str, QByteArray key){ bool pub=true; - if(key.contains("--BEGIN PUBLIC KEY--")){ pub=true; } + if(key.contains("PUBLIC KEY--")){ pub=true; } else if(key.contains(" PRIVATE KEY--")){ pub=false; } else{ return str; } //unknown encryption - just return as-is //return str.toLocal8Bit().toBase64(); //TEMPORARY BYPASS - //qDebug() << "Encrypt String:" << str << pub;//<< key; + //qDebug() << "Start encoding String:" << pub << str.length() << str << key; //Reset/Load some SSL stuff - OpenSSL_add_all_algorithms(); - ERR_load_crypto_strings(); + //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 + //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(keybio==NULL){ qDebug() << " - Bad keybio"; return ""; } + QString outstring; 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(); - //qDebug() << "Could reverse encoding:" << (decryptString(str_encode, key) == str); - return QString( str_encode ); - + if(rsa==NULL){ qDebug() << " - Bad rsa"; BIO_free_all(keybio); return ""; } + QJsonArray array; + int rsa_size = RSA_size(rsa)/2; + for(int i=0; i1){ outstring = QJsonDocument(array).toJson(QJsonDocument::Compact); } }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() << "==========CHECK Internal reverse encoding:"; - INTERNAL VERIFY WILL NEVER WORK: Public Key encrypt needs private key decrypt and vice-versa - QString tmp = decryptString(str_encode, key); - qDebug() << "INITIAL:" << str; - qDebug() << "Decoded:" << tmp; - qDebug() << "Match:" << ( tmp== str);*/ - //qDebug() << "Base64:" << str_encode; - return QString( str_encode ); + if(rsa==NULL){ qDebug() << " - Bad rsa"; BIO_free_all(keybio); return ""; } + QJsonArray array; + int rsa_size = RSA_size(rsa)/2; + for(int i=0; i1){ outstring = QJsonDocument(array).toJson(QJsonDocument::Compact); } } - return str; + return outstring; } QString AuthorizationManager::decryptString(QString str, QByteArray key){ bool pub=true; - if(key.contains("--BEGIN PUBLIC KEY--")){ pub=true; } + if(key.contains(" PUBLIC KEY--")){ pub=true; } else if(key.contains(" PRIVATE KEY--")){ pub=false; } - else{ return str; } //unknown encryption - just return as-is - //Turn back into data (Base64 required for encrypted transport) - QByteArray bytes; bytes.append(str); - bytes = QByteArray::fromBase64(bytes); - //qDebug() << "Decode String:" << bytes; + else{ //unknown encryption - just return as-is + if(!key.isEmpty()){ qDebug() << "Unknown key type!!" << key; } + return str; + } + //Convert the input string into block elements as needed (and decode base64); + QList blocks; + QJsonDocument doc = QJsonDocument::fromJson(str.toLocal8Bit()); + if(doc.isNull()){ + //No individual blocks - just one string + QByteArray bytes; bytes.append(str); + blocks << QByteArray::fromBase64(bytes); + }else if(doc.isArray()){ + for(int i=0; i AuthorizationManager::GenerateSSLKeyPair(){ - const int kBits = 4096; //25165824; // 3MB in bits + const int kBits = 4096; const int kExp = 3; char *pem_key, *pem_key_pub; @@ -456,21 +508,45 @@ QList AuthorizationManager::GenerateSSLKeyPair(){ BIO *bio = BIO_new(BIO_s_mem()); PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL); int keylen = BIO_pending(bio); - pem_key = (char *)malloc(keylen+1); /* Null-terminate */ + pem_key = (char *)malloc(keylen); /* Null-terminate */ BIO_read(bio, pem_key, keylen); QByteArray privkey = QByteArray::fromRawData(pem_key, keylen); //Public key in PEM form: BIO *bio2 = BIO_new(BIO_s_mem()); - PEM_write_bio_RSAPublicKey(bio2, rsa); + PEM_write_bio_RSA_PUBKEY(bio2, rsa); int keylen2 = BIO_pending(bio2); - pem_key_pub = (char *)malloc(keylen2+1); /* Null-terminate */ + pem_key_pub = (char *)malloc(keylen2); /* Null-terminate */ BIO_read(bio2, pem_key_pub, keylen2); QByteArray pubkey = QByteArray::fromRawData(pem_key_pub, keylen2); BIO_free_all(bio); BIO_free_all(bio2); RSA_free(rsa); + + //See if the keys can be loaded for use later + /*RSA *rsa1= NULL; + BIO *keybio1 = NULL; + //qDebug() << " - Generate keybio"; + keybio1 = BIO_new_mem_buf(pubkey.data(), -1); + if(keybio1!=NULL){ + rsa1 = PEM_read_bio_RSA_PUBKEY(keybio1, &rsa1,NULL, NULL); + qDebug() << "Can read new public key:" << (rsa1!=NULL); + RSA_free(rsa1); + } + BIO_free_all(keybio1); + + RSA *rsa2= NULL; + BIO *keybio2 = NULL; + //qDebug() << " - Generate keybio"; + keybio2 = BIO_new_mem_buf(privkey.data(), -1); + if(keybio2!=NULL){ + rsa2 = PEM_read_bio_RSAPrivateKey(keybio2, &rsa1,NULL, NULL); + qDebug() << "Can read new private key:" << (rsa2!=NULL); + RSA_free(rsa2); + } + BIO_free_all(keybio2); + */ return (QList() << pubkey << privkey); } diff --git a/src/server/WebSocket.cpp b/src/server/WebSocket.cpp index cea51ee..828c58d 100644 --- a/src/server/WebSocket.cpp +++ b/src/server/WebSocket.cpp @@ -256,7 +256,7 @@ 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"; + //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 @@ -264,30 +264,27 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){ //qDebug() << "New Check String:" << key; QJsonObject obj; if(out.in_struct.args.toObject().contains("md5_key")){ - qDebug() << "Encrypted SSL Auth Requested"; + //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"; QList newkeys = AUTHSYSTEM->GenerateSSLKeyPair(); //public[0]/private[1] - //Now break up the private key into 128 byte chunks and encrypt with public key for transport - //qDebug() << " - Destruct public key into chunks"; - QJsonArray pkeyarr; - for(int i=0; iencryptString( QString(newkeys[0].mid(i,128)), pubkey); - } - obj.insert("new_ssl_key", pkeyarr); //send this to the client for re-assembly (public key) + //qDebug() << "New Keys:"; + //qDebug() << newkeys[0] << "\n" << newkeys[1]; + obj.insert("new_ssl_key", AUTHSYSTEM->encryptString( QString(newkeys[0]), pubkey) ); //pkeyarr); //send this to the client for re-assembly (public key) //Also encrypt the test string with the public key as well //qDebug() << " - Encrypt test string with pubkey"; - qDebug() << "SSL Test String (raw):" << key; + //qDebug() << "SSL Test String (raw):" << key; key = AUTHSYSTEM->encryptString( key, pubkey); //qDebug() << " - Done with special SSL section"; - qDebug() << "SSL Test String (encrypted + encoded):" << key; - qDebug() << "SSL Test String (encrypted):" << QByteArray::fromBase64(key.toLocal8Bit()); + //qDebug() << "SSL Test String (encrypted + encoded):" << key; + //qDebug() << "SSL Test String (encrypted):" << QByteArray::fromBase64(key.toLocal8Bit()); + BRIDGE[REQ.bridgeID].enc_key = newkeys[1]; //keep private key + //BRIDGE[REQ.bridgeID].enc_key = pubkey; } - obj.insert("test_string", key); + obj.insert("test_string", QJsonValue(key)); out.out_args = obj; out.CODE = RestOutputStruct::OK; QString msg = out.assembleMessage();