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

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