You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CSecurityRSAAES.cxx 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. * Copyright (C) 2022 Dinglan Peng
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #ifndef HAVE_NETTLE
  23. #error "This header should not be compiled without HAVE_NETTLE defined"
  24. #endif
  25. #include <stdlib.h>
  26. #ifndef WIN32
  27. #include <unistd.h>
  28. #endif
  29. #include <assert.h>
  30. #include <nettle/bignum.h>
  31. #include <nettle/sha1.h>
  32. #include <nettle/sha2.h>
  33. #include <rfb/CSecurityRSAAES.h>
  34. #include <rfb/CConnection.h>
  35. #include <rfb/LogWriter.h>
  36. #include <rfb/Exception.h>
  37. #include <rfb/UserMsgBox.h>
  38. #include <rfb/util.h>
  39. #include <rdr/AESInStream.h>
  40. #include <rdr/AESOutStream.h>
  41. #include <os/os.h>
  42. enum {
  43. ReadPublicKey,
  44. ReadRandom,
  45. ReadHash,
  46. ReadSubtype,
  47. };
  48. const int MinKeyLength = 1024;
  49. const int MaxKeyLength = 8192;
  50. using namespace rfb;
  51. CSecurityRSAAES::CSecurityRSAAES(CConnection* cc, uint32_t _secType,
  52. int _keySize, bool _isAllEncrypted)
  53. : CSecurity(cc), state(ReadPublicKey),
  54. keySize(_keySize), isAllEncrypted(_isAllEncrypted), secType(_secType),
  55. clientKey(), clientPublicKey(), serverKey(),
  56. serverKeyN(NULL), serverKeyE(NULL),
  57. clientKeyN(NULL), clientKeyE(NULL),
  58. rais(NULL), raos(NULL), rawis(NULL), rawos(NULL)
  59. {
  60. assert(keySize == 128 || keySize == 256);
  61. }
  62. CSecurityRSAAES::~CSecurityRSAAES()
  63. {
  64. cleanup();
  65. }
  66. void CSecurityRSAAES::cleanup()
  67. {
  68. if (serverKeyN)
  69. delete[] serverKeyN;
  70. if (serverKeyE)
  71. delete[] serverKeyE;
  72. if (clientKeyN)
  73. delete[] clientKeyN;
  74. if (clientKeyE)
  75. delete[] clientKeyE;
  76. if (clientKey.size)
  77. rsa_private_key_clear(&clientKey);
  78. if (clientPublicKey.size)
  79. rsa_public_key_clear(&clientPublicKey);
  80. if (serverKey.size)
  81. rsa_public_key_clear(&serverKey);
  82. if (isAllEncrypted && rawis && rawos)
  83. cc->setStreams(rawis, rawos);
  84. if (rais)
  85. delete rais;
  86. if (raos)
  87. delete raos;
  88. }
  89. bool CSecurityRSAAES::processMsg()
  90. {
  91. switch (state) {
  92. case ReadPublicKey:
  93. if (!readPublicKey())
  94. return false;
  95. verifyServer();
  96. writePublicKey();
  97. writeRandom();
  98. state = ReadRandom;
  99. /* fall through */
  100. case ReadRandom:
  101. if (!readRandom())
  102. return false;
  103. setCipher();
  104. writeHash();
  105. state = ReadHash;
  106. /* fall through */
  107. case ReadHash:
  108. if (!readHash())
  109. return false;
  110. clearSecrets();
  111. state = ReadSubtype;
  112. /* fall through */
  113. case ReadSubtype:
  114. if (!readSubtype())
  115. return false;
  116. writeCredentials();
  117. return true;
  118. }
  119. assert(!"unreachable");
  120. return false;
  121. }
  122. static void random_func(void* ctx, size_t length, uint8_t* dst)
  123. {
  124. rdr::RandomStream* rs = (rdr::RandomStream*)ctx;
  125. if (!rs->hasData(length))
  126. throw ConnFailedException("failed to generate random");
  127. rs->readBytes(dst, length);
  128. }
  129. void CSecurityRSAAES::writePublicKey()
  130. {
  131. rdr::OutStream* os = cc->getOutStream();
  132. // generate client key
  133. rsa_public_key_init(&clientPublicKey);
  134. rsa_private_key_init(&clientKey);
  135. // match the server key size
  136. clientKeyLength = serverKeyLength;
  137. int rsaKeySize = (clientKeyLength + 7) / 8;
  138. // set key size to non-zero to allow clearing the keys when cleanup
  139. clientPublicKey.size = rsaKeySize;
  140. clientKey.size = rsaKeySize;
  141. // set e = 65537
  142. mpz_set_ui(clientPublicKey.e, 65537);
  143. if (!rsa_generate_keypair(&clientPublicKey, &clientKey,
  144. &rs, random_func, NULL, NULL, clientKeyLength, 0))
  145. throw AuthFailureException("failed to generate key");
  146. clientKeyN = new uint8_t[rsaKeySize];
  147. clientKeyE = new uint8_t[rsaKeySize];
  148. nettle_mpz_get_str_256(rsaKeySize, clientKeyN, clientPublicKey.n);
  149. nettle_mpz_get_str_256(rsaKeySize, clientKeyE, clientPublicKey.e);
  150. os->writeU32(clientKeyLength);
  151. os->writeBytes(clientKeyN, rsaKeySize);
  152. os->writeBytes(clientKeyE, rsaKeySize);
  153. os->flush();
  154. }
  155. bool CSecurityRSAAES::readPublicKey()
  156. {
  157. rdr::InStream* is = cc->getInStream();
  158. if (!is->hasData(4))
  159. return false;
  160. is->setRestorePoint();
  161. serverKeyLength = is->readU32();
  162. if (serverKeyLength < MinKeyLength)
  163. throw AuthFailureException("server key is too short");
  164. if (serverKeyLength > MaxKeyLength)
  165. throw AuthFailureException("server key is too long");
  166. size_t size = (serverKeyLength + 7) / 8;
  167. if (!is->hasDataOrRestore(size * 2))
  168. return false;
  169. is->clearRestorePoint();
  170. serverKeyE = new uint8_t[size];
  171. serverKeyN = new uint8_t[size];
  172. is->readBytes(serverKeyN, size);
  173. is->readBytes(serverKeyE, size);
  174. rsa_public_key_init(&serverKey);
  175. nettle_mpz_set_str_256_u(serverKey.n, size, serverKeyN);
  176. nettle_mpz_set_str_256_u(serverKey.e, size, serverKeyE);
  177. if (!rsa_public_key_prepare(&serverKey))
  178. throw AuthFailureException("server key is invalid");
  179. return true;
  180. }
  181. void CSecurityRSAAES::verifyServer()
  182. {
  183. uint8_t lenServerKey[4] = {
  184. (uint8_t)((serverKeyLength & 0xff000000) >> 24),
  185. (uint8_t)((serverKeyLength & 0xff0000) >> 16),
  186. (uint8_t)((serverKeyLength & 0xff00) >> 8),
  187. (uint8_t)(serverKeyLength & 0xff)
  188. };
  189. uint8_t f[8];
  190. struct sha1_ctx ctx;
  191. sha1_init(&ctx);
  192. sha1_update(&ctx, 4, lenServerKey);
  193. sha1_update(&ctx, serverKey.size, serverKeyN);
  194. sha1_update(&ctx, serverKey.size, serverKeyE);
  195. sha1_digest(&ctx, sizeof(f), f);
  196. const char *title = "Server key fingerprint";
  197. std::string text = format(
  198. "The server has provided the following identifying information:\n"
  199. "Fingerprint: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n"
  200. "Please verify that the information is correct and press \"Yes\". "
  201. "Otherwise press \"No\"", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]);
  202. if (!msg->showMsgBox(UserMsgBox::M_YESNO, title, text.c_str()))
  203. throw AuthFailureException("server key mismatch");
  204. }
  205. void CSecurityRSAAES::writeRandom()
  206. {
  207. rdr::OutStream* os = cc->getOutStream();
  208. if (!rs.hasData(keySize / 8))
  209. throw ConnFailedException("failed to generate random");
  210. rs.readBytes(clientRandom, keySize / 8);
  211. mpz_t x;
  212. mpz_init(x);
  213. int res;
  214. try {
  215. res = rsa_encrypt(&serverKey, &rs, random_func, keySize / 8,
  216. clientRandom, x);
  217. } catch (...) {
  218. mpz_clear(x);
  219. throw;
  220. }
  221. if (!res) {
  222. mpz_clear(x);
  223. throw AuthFailureException("failed to encrypt random");
  224. }
  225. uint8_t* buffer = new uint8_t[serverKey.size];
  226. nettle_mpz_get_str_256(serverKey.size, buffer, x);
  227. mpz_clear(x);
  228. os->writeU16(serverKey.size);
  229. os->writeBytes(buffer, serverKey.size);
  230. os->flush();
  231. delete[] buffer;
  232. }
  233. bool CSecurityRSAAES::readRandom()
  234. {
  235. rdr::InStream* is = cc->getInStream();
  236. if (!is->hasData(2))
  237. return false;
  238. is->setRestorePoint();
  239. size_t size = is->readU16();
  240. if (size != clientKey.size)
  241. throw AuthFailureException("client key length doesn't match");
  242. if (!is->hasDataOrRestore(size))
  243. return false;
  244. is->clearRestorePoint();
  245. uint8_t* buffer = new uint8_t[size];
  246. is->readBytes(buffer, size);
  247. size_t randomSize = keySize / 8;
  248. mpz_t x;
  249. nettle_mpz_init_set_str_256_u(x, size, buffer);
  250. delete[] buffer;
  251. if (!rsa_decrypt(&clientKey, &randomSize, serverRandom, x) ||
  252. randomSize != (size_t)keySize / 8) {
  253. mpz_clear(x);
  254. throw AuthFailureException("failed to decrypt server random");
  255. }
  256. mpz_clear(x);
  257. return true;
  258. }
  259. void CSecurityRSAAES::setCipher()
  260. {
  261. rawis = cc->getInStream();
  262. rawos = cc->getOutStream();
  263. uint8_t key[32];
  264. if (keySize == 128) {
  265. struct sha1_ctx ctx;
  266. sha1_init(&ctx);
  267. sha1_update(&ctx, 16, clientRandom);
  268. sha1_update(&ctx, 16, serverRandom);
  269. sha1_digest(&ctx, 16, key);
  270. rais = new rdr::AESInStream(rawis, key, 128);
  271. sha1_init(&ctx);
  272. sha1_update(&ctx, 16, serverRandom);
  273. sha1_update(&ctx, 16, clientRandom);
  274. sha1_digest(&ctx, 16, key);
  275. raos = new rdr::AESOutStream(rawos, key, 128);
  276. } else {
  277. struct sha256_ctx ctx;
  278. sha256_init(&ctx);
  279. sha256_update(&ctx, 32, clientRandom);
  280. sha256_update(&ctx, 32, serverRandom);
  281. sha256_digest(&ctx, 32, key);
  282. rais = new rdr::AESInStream(rawis, key, 256);
  283. sha256_init(&ctx);
  284. sha256_update(&ctx, 32, serverRandom);
  285. sha256_update(&ctx, 32, clientRandom);
  286. sha256_digest(&ctx, 32, key);
  287. raos = new rdr::AESOutStream(rawos, key, 256);
  288. }
  289. if (isAllEncrypted)
  290. cc->setStreams(rais, raos);
  291. }
  292. void CSecurityRSAAES::writeHash()
  293. {
  294. uint8_t hash[32];
  295. size_t len = serverKeyLength;
  296. uint8_t lenServerKey[4] = {
  297. (uint8_t)((len & 0xff000000) >> 24),
  298. (uint8_t)((len & 0xff0000) >> 16),
  299. (uint8_t)((len & 0xff00) >> 8),
  300. (uint8_t)(len & 0xff)
  301. };
  302. len = clientKeyLength;
  303. uint8_t lenClientKey[4] = {
  304. (uint8_t)((len & 0xff000000) >> 24),
  305. (uint8_t)((len & 0xff0000) >> 16),
  306. (uint8_t)((len & 0xff00) >> 8),
  307. (uint8_t)(len & 0xff)
  308. };
  309. int hashSize;
  310. if (keySize == 128) {
  311. hashSize = 20;
  312. struct sha1_ctx ctx;
  313. sha1_init(&ctx);
  314. sha1_update(&ctx, 4, lenClientKey);
  315. sha1_update(&ctx, clientKey.size, clientKeyN);
  316. sha1_update(&ctx, clientKey.size, clientKeyE);
  317. sha1_update(&ctx, 4, lenServerKey);
  318. sha1_update(&ctx, serverKey.size, serverKeyN);
  319. sha1_update(&ctx, serverKey.size, serverKeyE);
  320. sha1_digest(&ctx, hashSize, hash);
  321. } else {
  322. hashSize = 32;
  323. struct sha256_ctx ctx;
  324. sha256_init(&ctx);
  325. sha256_update(&ctx, 4, lenClientKey);
  326. sha256_update(&ctx, clientKey.size, clientKeyN);
  327. sha256_update(&ctx, clientKey.size, clientKeyE);
  328. sha256_update(&ctx, 4, lenServerKey);
  329. sha256_update(&ctx, serverKey.size, serverKeyN);
  330. sha256_update(&ctx, serverKey.size, serverKeyE);
  331. sha256_digest(&ctx, hashSize, hash);
  332. }
  333. raos->writeBytes(hash, hashSize);
  334. raos->flush();
  335. }
  336. bool CSecurityRSAAES::readHash()
  337. {
  338. uint8_t hash[32];
  339. uint8_t realHash[32];
  340. int hashSize = keySize == 128 ? 20 : 32;
  341. if (!rais->hasData(hashSize))
  342. return false;
  343. rais->readBytes(hash, hashSize);
  344. size_t len = serverKeyLength;
  345. uint8_t lenServerKey[4] = {
  346. (uint8_t)((len & 0xff000000) >> 24),
  347. (uint8_t)((len & 0xff0000) >> 16),
  348. (uint8_t)((len & 0xff00) >> 8),
  349. (uint8_t)(len & 0xff)
  350. };
  351. len = clientKeyLength;
  352. uint8_t lenClientKey[4] = {
  353. (uint8_t)((len & 0xff000000) >> 24),
  354. (uint8_t)((len & 0xff0000) >> 16),
  355. (uint8_t)((len & 0xff00) >> 8),
  356. (uint8_t)(len & 0xff)
  357. };
  358. if (keySize == 128) {
  359. struct sha1_ctx ctx;
  360. sha1_init(&ctx);
  361. sha1_update(&ctx, 4, lenServerKey);
  362. sha1_update(&ctx, serverKey.size, serverKeyN);
  363. sha1_update(&ctx, serverKey.size, serverKeyE);
  364. sha1_update(&ctx, 4, lenClientKey);
  365. sha1_update(&ctx, clientKey.size, clientKeyN);
  366. sha1_update(&ctx, clientKey.size, clientKeyE);
  367. sha1_digest(&ctx, hashSize, realHash);
  368. } else {
  369. struct sha256_ctx ctx;
  370. sha256_init(&ctx);
  371. sha256_update(&ctx, 4, lenServerKey);
  372. sha256_update(&ctx, serverKey.size, serverKeyN);
  373. sha256_update(&ctx, serverKey.size, serverKeyE);
  374. sha256_update(&ctx, 4, lenClientKey);
  375. sha256_update(&ctx, clientKey.size, clientKeyN);
  376. sha256_update(&ctx, clientKey.size, clientKeyE);
  377. sha256_digest(&ctx, hashSize, realHash);
  378. }
  379. if (memcmp(hash, realHash, hashSize) != 0)
  380. throw AuthFailureException("hash doesn't match");
  381. return true;
  382. }
  383. void CSecurityRSAAES::clearSecrets()
  384. {
  385. rsa_private_key_clear(&clientKey);
  386. rsa_public_key_clear(&clientPublicKey);
  387. rsa_public_key_clear(&serverKey);
  388. clientKey.size = 0;
  389. clientPublicKey.size = 0;
  390. serverKey.size = 0;
  391. delete[] serverKeyN;
  392. delete[] serverKeyE;
  393. delete[] clientKeyN;
  394. delete[] clientKeyE;
  395. serverKeyN = NULL;
  396. serverKeyE = NULL;
  397. clientKeyN = NULL;
  398. clientKeyE = NULL;
  399. memset(serverRandom, 0, sizeof(serverRandom));
  400. memset(clientRandom, 0, sizeof(clientRandom));
  401. }
  402. bool CSecurityRSAAES::readSubtype()
  403. {
  404. if (!rais->hasData(1))
  405. return false;
  406. subtype = rais->readU8();
  407. if (subtype != secTypeRA2UserPass && subtype != secTypeRA2Pass)
  408. throw AuthFailureException("unknown RSA-AES subtype");
  409. return true;
  410. }
  411. void CSecurityRSAAES::writeCredentials()
  412. {
  413. std::string username;
  414. std::string password;
  415. if (subtype == secTypeRA2UserPass)
  416. (CSecurity::upg)->getUserPasswd(isSecure(), &username, &password);
  417. else
  418. (CSecurity::upg)->getUserPasswd(isSecure(), NULL, &password);
  419. if (subtype == secTypeRA2UserPass) {
  420. if (username.size() > 255)
  421. throw AuthFailureException("username is too long");
  422. raos->writeU8(username.size());
  423. raos->writeBytes((const uint8_t*)username.data(), username.size());
  424. } else {
  425. raos->writeU8(0);
  426. }
  427. if (password.size() > 255)
  428. throw AuthFailureException("password is too long");
  429. raos->writeU8(password.size());
  430. raos->writeBytes((const uint8_t*)password.data(), password.size());
  431. raos->flush();
  432. }