endif() | endif() | ||||
if (NETTLE_FOUND) | if (NETTLE_FOUND) | ||||
target_sources(rfb PRIVATE CSecurityDH.cxx | |||||
target_sources(rfb PRIVATE CSecurityDH.cxx CSecurityMSLogonII.cxx | |||||
CSecurityRSAAES.cxx SSecurityRSAAES.cxx) | CSecurityRSAAES.cxx SSecurityRSAAES.cxx) | ||||
include_directories(${NETTLE_INCLUDE_DIRS} ${GMP_INCLUDE_DIRS}) | include_directories(${NETTLE_INCLUDE_DIRS} ${GMP_INCLUDE_DIRS}) | ||||
target_link_libraries(rfb ${HOGWEED_LIBRARIES} | target_link_libraries(rfb ${HOGWEED_LIBRARIES} |
/* | |||||
* Copyright (C) 2022 Dinglan Peng | |||||
* | |||||
* This is free software; you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation; either version 2 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* This software is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with this software; if not, write to the Free Software | |||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||||
* USA. | |||||
*/ | |||||
#ifdef HAVE_CONFIG_H | |||||
#include <config.h> | |||||
#endif | |||||
#ifndef HAVE_NETTLE | |||||
#error "This header should not be compiled without HAVE_NETTLE defined" | |||||
#endif | |||||
#include <stdlib.h> | |||||
#ifndef WIN32 | |||||
#include <unistd.h> | |||||
#endif | |||||
#include <assert.h> | |||||
#include <nettle/des.h> | |||||
#include <nettle/cbc.h> | |||||
#include <nettle/bignum.h> | |||||
#include <rfb/CSecurityMSLogonII.h> | |||||
#include <rfb/CConnection.h> | |||||
#include <rdr/InStream.h> | |||||
#include <rdr/OutStream.h> | |||||
#include <rdr/RandomStream.h> | |||||
#include <rfb/Exception.h> | |||||
#include <os/os.h> | |||||
using namespace rfb; | |||||
CSecurityMSLogonII::CSecurityMSLogonII(CConnection* cc) | |||||
: CSecurity(cc) | |||||
{ | |||||
mpz_init(g); | |||||
mpz_init(p); | |||||
mpz_init(A); | |||||
mpz_init(b); | |||||
mpz_init(B); | |||||
mpz_init(k); | |||||
} | |||||
CSecurityMSLogonII::~CSecurityMSLogonII() | |||||
{ | |||||
mpz_clear(g); | |||||
mpz_clear(p); | |||||
mpz_clear(A); | |||||
mpz_clear(b); | |||||
mpz_clear(B); | |||||
mpz_clear(k); | |||||
} | |||||
bool CSecurityMSLogonII::processMsg() | |||||
{ | |||||
if (readKey()) { | |||||
writeCredentials(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
bool CSecurityMSLogonII::readKey() | |||||
{ | |||||
rdr::InStream* is = cc->getInStream(); | |||||
if (!is->hasData(24)) | |||||
return false; | |||||
rdr::U8 gBytes[8]; | |||||
rdr::U8 pBytes[8]; | |||||
rdr::U8 ABytes[8]; | |||||
is->readBytes(gBytes, 8); | |||||
is->readBytes(pBytes, 8); | |||||
is->readBytes(ABytes, 8); | |||||
nettle_mpz_set_str_256_u(g, 8, gBytes); | |||||
nettle_mpz_set_str_256_u(p, 8, pBytes); | |||||
nettle_mpz_set_str_256_u(A, 8, ABytes); | |||||
return true; | |||||
} | |||||
void CSecurityMSLogonII::writeCredentials() | |||||
{ | |||||
CharArray username; | |||||
CharArray password; | |||||
rdr::RandomStream rs; | |||||
(CSecurity::upg)->getUserPasswd(isSecure(), &username.buf, &password.buf); | |||||
rdr::U8Array bBytes(8); | |||||
if (!rs.hasData(8)) | |||||
throw ConnFailedException("failed to generate DH private key"); | |||||
rs.readBytes(bBytes.buf, 8); | |||||
nettle_mpz_set_str_256_u(b, 8, bBytes.buf); | |||||
mpz_powm(k, A, b, p); | |||||
mpz_powm(B, g, b, p); | |||||
rdr::U8 key[8]; | |||||
rdr::U8 reversedKey[8]; | |||||
rdr::U8 BBytes[8]; | |||||
rdr::U8 user[256]; | |||||
rdr::U8 pass[64]; | |||||
nettle_mpz_get_str_256(8, key, k); | |||||
nettle_mpz_get_str_256(8, BBytes, B); | |||||
for (int i = 0; i < 8; ++i) { | |||||
rdr::U8 x = 0; | |||||
for (int j = 0; j < 8; ++j) { | |||||
x |= ((key[i] >> j) & 1) << (7 - j); | |||||
} | |||||
reversedKey[i] = x; | |||||
} | |||||
if (!rs.hasData(256 + 64)) | |||||
throw ConnFailedException("failed to generate random padding"); | |||||
rs.readBytes(user, 256); | |||||
rs.readBytes(pass, 64); | |||||
size_t len = strlen(username.buf); | |||||
if (len >= 256) | |||||
throw AuthFailureException("username is too long"); | |||||
memcpy(user, username.buf, len + 1); | |||||
len = strlen(password.buf); | |||||
if (len >= 64) | |||||
throw AuthFailureException("password is too long"); | |||||
memcpy(pass, password.buf, len + 1); | |||||
// DES-CBC with the original key as IV, and the reversed one as the DES key | |||||
struct CBC_CTX(struct des_ctx, DES_BLOCK_SIZE) ctx; | |||||
des_fix_parity(8, reversedKey, reversedKey); | |||||
des_set_key(&ctx.ctx, reversedKey); | |||||
CBC_SET_IV(&ctx, key); | |||||
CBC_ENCRYPT(&ctx, des_encrypt, 256, user, user); | |||||
CBC_SET_IV(&ctx, key); | |||||
CBC_ENCRYPT(&ctx, des_encrypt, 64, pass, pass); | |||||
rdr::OutStream* os = cc->getOutStream(); | |||||
os->writeBytes(BBytes, 8); | |||||
os->writeBytes(user, 256); | |||||
os->writeBytes(pass, 64); | |||||
os->flush(); | |||||
} |
/* | |||||
* Copyright (C) 2022 Dinglan Peng | |||||
* | |||||
* This is free software; you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation; either version 2 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* This software is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with this software; if not, write to the Free Software | |||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||||
* USA. | |||||
*/ | |||||
#ifndef __C_SECURITY_MSLOGONII_H__ | |||||
#define __C_SECURITY_MSLOGONII_H__ | |||||
#ifndef HAVE_NETTLE | |||||
#error "This header should not be compiled without HAVE_NETTLE defined" | |||||
#endif | |||||
#include <nettle/bignum.h> | |||||
#include <rfb/CSecurity.h> | |||||
#include <rfb/Security.h> | |||||
namespace rfb { | |||||
class CSecurityMSLogonII : public CSecurity { | |||||
public: | |||||
CSecurityMSLogonII(CConnection* cc); | |||||
virtual ~CSecurityMSLogonII(); | |||||
virtual bool processMsg(); | |||||
virtual int getType() const { return secTypeMSLogonII; } | |||||
virtual bool isSecure() const { return false; } | |||||
private: | |||||
bool readKey(); | |||||
void writeCredentials(); | |||||
mpz_t g, p, A, b, B, k; | |||||
}; | |||||
} | |||||
#endif |
if (strcasecmp(name, "SSPIne") == 0) return secTypeSSPIne; | if (strcasecmp(name, "SSPIne") == 0) return secTypeSSPIne; | ||||
if (strcasecmp(name, "VeNCrypt") == 0) return secTypeVeNCrypt; | if (strcasecmp(name, "VeNCrypt") == 0) return secTypeVeNCrypt; | ||||
if (strcasecmp(name, "DH") == 0) return secTypeDH; | if (strcasecmp(name, "DH") == 0) return secTypeDH; | ||||
if (strcasecmp(name, "MSLogonII") == 0) return secTypeMSLogonII; | |||||
/* VeNCrypt subtypes */ | /* VeNCrypt subtypes */ | ||||
if (strcasecmp(name, "Plain") == 0) return secTypePlain; | if (strcasecmp(name, "Plain") == 0) return secTypePlain; | ||||
case secTypeSSPIne: return "SSPIne"; | case secTypeSSPIne: return "SSPIne"; | ||||
case secTypeVeNCrypt: return "VeNCrypt"; | case secTypeVeNCrypt: return "VeNCrypt"; | ||||
case secTypeDH: return "DH"; | case secTypeDH: return "DH"; | ||||
case secTypeMSLogonII: return "MSLogonII"; | |||||
/* VeNCrypt subtypes */ | /* VeNCrypt subtypes */ | ||||
case secTypePlain: return "Plain"; | case secTypePlain: return "Plain"; |
#include <list> | #include <list> | ||||
namespace rfb { | namespace rfb { | ||||
const rdr::U8 secTypeInvalid = 0; | |||||
const rdr::U8 secTypeNone = 1; | |||||
const rdr::U8 secTypeVncAuth = 2; | |||||
const rdr::U8 secTypeInvalid = 0; | |||||
const rdr::U8 secTypeNone = 1; | |||||
const rdr::U8 secTypeVncAuth = 2; | |||||
const rdr::U8 secTypeRA2 = 5; | |||||
const rdr::U8 secTypeRA2ne = 6; | |||||
const rdr::U8 secTypeRA2 = 5; | |||||
const rdr::U8 secTypeRA2ne = 6; | |||||
const rdr::U8 secTypeSSPI = 7; | |||||
const rdr::U8 secTypeSSPIne = 8; | |||||
const rdr::U8 secTypeSSPI = 7; | |||||
const rdr::U8 secTypeSSPIne = 8; | |||||
const rdr::U8 secTypeTight = 16; | |||||
const rdr::U8 secTypeUltra = 17; | |||||
const rdr::U8 secTypeTLS = 18; | |||||
const rdr::U8 secTypeVeNCrypt= 19; | |||||
const rdr::U8 secTypeTight = 16; | |||||
const rdr::U8 secTypeUltra = 17; | |||||
const rdr::U8 secTypeTLS = 18; | |||||
const rdr::U8 secTypeVeNCrypt = 19; | |||||
const rdr::U8 secTypeDH = 30; | |||||
const rdr::U8 secTypeDH = 30; | |||||
const rdr::U8 secTypeRA256 = 129; | |||||
const rdr::U8 secTypeRAne256 = 130; | |||||
const rdr::U8 secTypeMSLogonII = 113; | |||||
const rdr::U8 secTypeRA256 = 129; | |||||
const rdr::U8 secTypeRAne256 = 130; | |||||
/* VeNCrypt subtypes */ | /* VeNCrypt subtypes */ | ||||
const int secTypePlain = 256; | |||||
const int secTypeTLSNone = 257; | |||||
const int secTypeTLSVnc = 258; | |||||
const int secTypeTLSPlain = 259; | |||||
const int secTypeX509None = 260; | |||||
const int secTypeX509Vnc = 261; | |||||
const int secTypeX509Plain = 262; | |||||
const int secTypePlain = 256; | |||||
const int secTypeTLSNone = 257; | |||||
const int secTypeTLSVnc = 258; | |||||
const int secTypeTLSPlain = 259; | |||||
const int secTypeX509None = 260; | |||||
const int secTypeX509Vnc = 261; | |||||
const int secTypeX509Plain = 262; | |||||
/* RSA-AES subtypes */ | /* RSA-AES subtypes */ | ||||
const int secTypeRA2UserPass = 1; | |||||
const int secTypeRA2Pass = 2; | |||||
const int secTypeRA2UserPass = 1; | |||||
const int secTypeRA2Pass = 2; | |||||
// result types | // result types | ||||
#ifdef HAVE_NETTLE | #ifdef HAVE_NETTLE | ||||
#include <rfb/CSecurityRSAAES.h> | #include <rfb/CSecurityRSAAES.h> | ||||
#include <rfb/CSecurityDH.h> | #include <rfb/CSecurityDH.h> | ||||
#include <rfb/CSecurityMSLogonII.h> | |||||
#endif | #endif | ||||
using namespace rdr; | using namespace rdr; | ||||
", TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, X509Plain" | ", TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, X509Plain" | ||||
#endif | #endif | ||||
#ifdef HAVE_NETTLE | #ifdef HAVE_NETTLE | ||||
", RA2, RA2ne, RA2_256, RA2ne_256, DH" | |||||
", RA2, RA2ne, RA2_256, RA2ne_256, DH, MSLogonII" | |||||
#endif | #endif | ||||
")", | ")", | ||||
#ifdef HAVE_GNUTLS | #ifdef HAVE_GNUTLS | ||||
"X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone," | "X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone," | ||||
#endif | #endif | ||||
#ifdef HAVE_NETTLE | #ifdef HAVE_NETTLE | ||||
"RA2,RA2_256,RA2ne,RA2ne_256,DH" | |||||
"RA2,RA2_256,RA2ne,RA2ne_256,DH,MSLogonII" | |||||
#endif | #endif | ||||
"VncAuth,None", | "VncAuth,None", | ||||
ConfViewer); | ConfViewer); | ||||
return new CSecurityRSAAES(cc, secTypeRAne256, 256, false); | return new CSecurityRSAAES(cc, secTypeRAne256, 256, false); | ||||
case secTypeDH: | case secTypeDH: | ||||
return new CSecurityDH(cc); | return new CSecurityDH(cc); | ||||
case secTypeMSLogonII: | |||||
return new CSecurityMSLogonII(cc); | |||||
#endif | #endif | ||||
} | } | ||||
case secTypeRAne256: | case secTypeRAne256: | ||||
authVncCheckbox->value(true); | authVncCheckbox->value(true); | ||||
case secTypeDH: | case secTypeDH: | ||||
case secTypeMSLogonII: | |||||
encNoneCheckbox->value(true); | encNoneCheckbox->value(true); | ||||
authPlainCheckbox->value(true); | authPlainCheckbox->value(true); | ||||
break; | break; | ||||
security.EnableSecType(secTypeRA2ne); | security.EnableSecType(secTypeRA2ne); | ||||
security.EnableSecType(secTypeRAne256); | security.EnableSecType(secTypeRAne256); | ||||
security.EnableSecType(secTypeDH); | security.EnableSecType(secTypeDH); | ||||
security.EnableSecType(secTypeMSLogonII); | |||||
#endif | #endif | ||||
} | } | ||||
} | } |