crypto.js 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607
  1. // TODO:
  2. // * make max packet size configurable
  3. // * if decompression is enabled, use `._packet` in decipher instances as
  4. // input to (sync) zlib inflater with appropriate offset and length to
  5. // avoid an additional copy of payload data before inflation
  6. // * factor decompression status into packet length checks
  7. 'use strict';
  8. const {
  9. createCipheriv, createDecipheriv, createHmac, randomFillSync, timingSafeEqual
  10. } = require('crypto');
  11. const { readUInt32BE, writeUInt32BE } = require('./utils.js');
  12. const FastBuffer = Buffer[Symbol.species];
  13. const MAX_SEQNO = 2 ** 32 - 1;
  14. const EMPTY_BUFFER = Buffer.alloc(0);
  15. const BUF_INT = Buffer.alloc(4);
  16. const DISCARD_CACHE = new Map();
  17. const MAX_PACKET_SIZE = 35000;
  18. let binding;
  19. let AESGCMCipher;
  20. let ChaChaPolyCipher;
  21. let GenericCipher;
  22. let AESGCMDecipher;
  23. let ChaChaPolyDecipher;
  24. let GenericDecipher;
  25. try {
  26. binding = require('./crypto/build/Release/sshcrypto.node');
  27. ({ AESGCMCipher, ChaChaPolyCipher, GenericCipher,
  28. AESGCMDecipher, ChaChaPolyDecipher, GenericDecipher } = binding);
  29. } catch {}
  30. const CIPHER_STREAM = 1 << 0;
  31. const CIPHER_INFO = (() => {
  32. function info(sslName, blockLen, keyLen, ivLen, authLen, discardLen, flags) {
  33. return {
  34. sslName,
  35. blockLen,
  36. keyLen,
  37. ivLen: (ivLen !== 0 || (flags & CIPHER_STREAM)
  38. ? ivLen
  39. : blockLen),
  40. authLen,
  41. discardLen,
  42. stream: !!(flags & CIPHER_STREAM),
  43. };
  44. }
  45. return {
  46. 'chacha20-poly1305@openssh.com':
  47. info('chacha20', 8, 64, 0, 16, 0, CIPHER_STREAM),
  48. 'aes128-gcm': info('aes-128-gcm', 16, 16, 12, 16, 0, CIPHER_STREAM),
  49. 'aes256-gcm': info('aes-256-gcm', 16, 32, 12, 16, 0, CIPHER_STREAM),
  50. 'aes128-gcm@openssh.com':
  51. info('aes-128-gcm', 16, 16, 12, 16, 0, CIPHER_STREAM),
  52. 'aes256-gcm@openssh.com':
  53. info('aes-256-gcm', 16, 32, 12, 16, 0, CIPHER_STREAM),
  54. 'aes128-cbc': info('aes-128-cbc', 16, 16, 0, 0, 0, 0),
  55. 'aes192-cbc': info('aes-192-cbc', 16, 24, 0, 0, 0, 0),
  56. 'aes256-cbc': info('aes-256-cbc', 16, 32, 0, 0, 0, 0),
  57. 'rijndael-cbc@lysator.liu.se': info('aes-256-cbc', 16, 32, 0, 0, 0, 0),
  58. '3des-cbc': info('des-ede3-cbc', 8, 24, 0, 0, 0, 0),
  59. 'blowfish-cbc': info('bf-cbc', 8, 16, 0, 0, 0, 0),
  60. 'idea-cbc': info('idea-cbc', 8, 16, 0, 0, 0, 0),
  61. 'cast128-cbc': info('cast-cbc', 8, 16, 0, 0, 0, 0),
  62. 'aes128-ctr': info('aes-128-ctr', 16, 16, 16, 0, 0, CIPHER_STREAM),
  63. 'aes192-ctr': info('aes-192-ctr', 16, 24, 16, 0, 0, CIPHER_STREAM),
  64. 'aes256-ctr': info('aes-256-ctr', 16, 32, 16, 0, 0, CIPHER_STREAM),
  65. '3des-ctr': info('des-ede3', 8, 24, 8, 0, 0, CIPHER_STREAM),
  66. 'blowfish-ctr': info('bf-ecb', 8, 16, 8, 0, 0, CIPHER_STREAM),
  67. 'cast128-ctr': info('cast5-ecb', 8, 16, 8, 0, 0, CIPHER_STREAM),
  68. /* The "arcfour128" algorithm is the RC4 cipher, as described in
  69. [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
  70. generated by the cipher MUST be discarded, and the first byte of the
  71. first encrypted packet MUST be encrypted using the 1537th byte of
  72. keystream.
  73. -- http://tools.ietf.org/html/rfc4345#section-4 */
  74. 'arcfour': info('rc4', 8, 16, 0, 0, 1536, CIPHER_STREAM),
  75. 'arcfour128': info('rc4', 8, 16, 0, 0, 1536, CIPHER_STREAM),
  76. 'arcfour256': info('rc4', 8, 32, 0, 0, 1536, CIPHER_STREAM),
  77. 'arcfour512': info('rc4', 8, 64, 0, 0, 1536, CIPHER_STREAM),
  78. };
  79. })();
  80. const MAC_INFO = (() => {
  81. function info(sslName, len, actualLen, isETM) {
  82. return {
  83. sslName,
  84. len,
  85. actualLen,
  86. isETM,
  87. };
  88. }
  89. return {
  90. 'hmac-md5': info('md5', 16, 16, false),
  91. 'hmac-md5-96': info('md5', 16, 12, false),
  92. 'hmac-ripemd160': info('ripemd160', 20, 20, false),
  93. 'hmac-sha1': info('sha1', 20, 20, false),
  94. 'hmac-sha1-etm@openssh.com': info('sha1', 20, 20, true),
  95. 'hmac-sha1-96': info('sha1', 20, 12, false),
  96. 'hmac-sha2-256': info('sha256', 32, 32, false),
  97. 'hmac-sha2-256-etm@openssh.com': info('sha256', 32, 32, true),
  98. 'hmac-sha2-256-96': info('sha256', 32, 12, false),
  99. 'hmac-sha2-512': info('sha512', 64, 64, false),
  100. 'hmac-sha2-512-etm@openssh.com': info('sha512', 64, 64, true),
  101. 'hmac-sha2-512-96': info('sha512', 64, 12, false),
  102. };
  103. })();
  104. // Should only_be used during the initial handshake
  105. class NullCipher {
  106. constructor(seqno, onWrite) {
  107. this.outSeqno = seqno;
  108. this._onWrite = onWrite;
  109. this._dead = false;
  110. }
  111. free() {
  112. this._dead = true;
  113. }
  114. allocPacket(payloadLen) {
  115. let pktLen = 4 + 1 + payloadLen;
  116. let padLen = 8 - (pktLen & (8 - 1));
  117. if (padLen < 4)
  118. padLen += 8;
  119. pktLen += padLen;
  120. const packet = Buffer.allocUnsafe(pktLen);
  121. writeUInt32BE(packet, pktLen - 4, 0);
  122. packet[4] = padLen;
  123. randomFillSync(packet, 5 + payloadLen, padLen);
  124. return packet;
  125. }
  126. encrypt(packet) {
  127. // `packet` === unencrypted packet
  128. if (this._dead)
  129. return;
  130. this._onWrite(packet);
  131. this.outSeqno = (this.outSeqno + 1) >>> 0;
  132. }
  133. }
  134. const POLY1305_ZEROS = Buffer.alloc(32);
  135. const POLY1305_OUT_COMPUTE = Buffer.alloc(16);
  136. let POLY1305_WASM_MODULE;
  137. let POLY1305_RESULT_MALLOC;
  138. let poly1305_auth;
  139. class ChaChaPolyCipherNative {
  140. constructor(config) {
  141. const enc = config.outbound;
  142. this.outSeqno = enc.seqno;
  143. this._onWrite = enc.onWrite;
  144. this._encKeyMain = enc.cipherKey.slice(0, 32);
  145. this._encKeyPktLen = enc.cipherKey.slice(32);
  146. this._dead = false;
  147. }
  148. free() {
  149. this._dead = true;
  150. }
  151. allocPacket(payloadLen) {
  152. let pktLen = 4 + 1 + payloadLen;
  153. let padLen = 8 - ((pktLen - 4) & (8 - 1));
  154. if (padLen < 4)
  155. padLen += 8;
  156. pktLen += padLen;
  157. const packet = Buffer.allocUnsafe(pktLen);
  158. writeUInt32BE(packet, pktLen - 4, 0);
  159. packet[4] = padLen;
  160. randomFillSync(packet, 5 + payloadLen, padLen);
  161. return packet;
  162. }
  163. encrypt(packet) {
  164. // `packet` === unencrypted packet
  165. if (this._dead)
  166. return;
  167. // Generate Poly1305 key
  168. POLY1305_OUT_COMPUTE[0] = 0; // Set counter to 0 (little endian)
  169. writeUInt32BE(POLY1305_OUT_COMPUTE, this.outSeqno, 12);
  170. const polyKey =
  171. createCipheriv('chacha20', this._encKeyMain, POLY1305_OUT_COMPUTE)
  172. .update(POLY1305_ZEROS);
  173. // Encrypt packet length
  174. const pktLenEnc =
  175. createCipheriv('chacha20', this._encKeyPktLen, POLY1305_OUT_COMPUTE)
  176. .update(packet.slice(0, 4));
  177. this._onWrite(pktLenEnc);
  178. // Encrypt rest of packet
  179. POLY1305_OUT_COMPUTE[0] = 1; // Set counter to 1 (little endian)
  180. const payloadEnc =
  181. createCipheriv('chacha20', this._encKeyMain, POLY1305_OUT_COMPUTE)
  182. .update(packet.slice(4));
  183. this._onWrite(payloadEnc);
  184. // Calculate Poly1305 MAC
  185. poly1305_auth(POLY1305_RESULT_MALLOC,
  186. pktLenEnc,
  187. pktLenEnc.length,
  188. payloadEnc,
  189. payloadEnc.length,
  190. polyKey);
  191. const mac = Buffer.allocUnsafe(16);
  192. mac.set(
  193. new Uint8Array(POLY1305_WASM_MODULE.HEAPU8.buffer,
  194. POLY1305_RESULT_MALLOC,
  195. 16),
  196. 0
  197. );
  198. this._onWrite(mac);
  199. this.outSeqno = (this.outSeqno + 1) >>> 0;
  200. }
  201. }
  202. class ChaChaPolyCipherBinding {
  203. constructor(config) {
  204. const enc = config.outbound;
  205. this.outSeqno = enc.seqno;
  206. this._onWrite = enc.onWrite;
  207. this._instance = new ChaChaPolyCipher(enc.cipherKey);
  208. this._dead = false;
  209. }
  210. free() {
  211. this._dead = true;
  212. this._instance.free();
  213. }
  214. allocPacket(payloadLen) {
  215. let pktLen = 4 + 1 + payloadLen;
  216. let padLen = 8 - ((pktLen - 4) & (8 - 1));
  217. if (padLen < 4)
  218. padLen += 8;
  219. pktLen += padLen;
  220. const packet = Buffer.allocUnsafe(pktLen + 16/* MAC */);
  221. writeUInt32BE(packet, pktLen - 4, 0);
  222. packet[4] = padLen;
  223. randomFillSync(packet, 5 + payloadLen, padLen);
  224. return packet;
  225. }
  226. encrypt(packet) {
  227. // `packet` === unencrypted packet
  228. if (this._dead)
  229. return;
  230. // Encrypts in-place
  231. this._instance.encrypt(packet, this.outSeqno);
  232. this._onWrite(packet);
  233. this.outSeqno = (this.outSeqno + 1) >>> 0;
  234. }
  235. }
  236. class AESGCMCipherNative {
  237. constructor(config) {
  238. const enc = config.outbound;
  239. this.outSeqno = enc.seqno;
  240. this._onWrite = enc.onWrite;
  241. this._encSSLName = enc.cipherInfo.sslName;
  242. this._encKey = enc.cipherKey;
  243. this._encIV = enc.cipherIV;
  244. this._dead = false;
  245. }
  246. free() {
  247. this._dead = true;
  248. }
  249. allocPacket(payloadLen) {
  250. let pktLen = 4 + 1 + payloadLen;
  251. let padLen = 16 - ((pktLen - 4) & (16 - 1));
  252. if (padLen < 4)
  253. padLen += 16;
  254. pktLen += padLen;
  255. const packet = Buffer.allocUnsafe(pktLen);
  256. writeUInt32BE(packet, pktLen - 4, 0);
  257. packet[4] = padLen;
  258. randomFillSync(packet, 5 + payloadLen, padLen);
  259. return packet;
  260. }
  261. encrypt(packet) {
  262. // `packet` === unencrypted packet
  263. if (this._dead)
  264. return;
  265. const cipher = createCipheriv(this._encSSLName, this._encKey, this._encIV);
  266. cipher.setAutoPadding(false);
  267. const lenData = packet.slice(0, 4);
  268. cipher.setAAD(lenData);
  269. this._onWrite(lenData);
  270. // Encrypt pad length, payload, and padding
  271. const encrypted = cipher.update(packet.slice(4));
  272. this._onWrite(encrypted);
  273. const final = cipher.final();
  274. // XXX: final.length === 0 always?
  275. if (final.length)
  276. this._onWrite(final);
  277. // Generate MAC
  278. const tag = cipher.getAuthTag();
  279. this._onWrite(tag);
  280. // Increment counter in IV by 1 for next packet
  281. ivIncrement(this._encIV);
  282. this.outSeqno = (this.outSeqno + 1) >>> 0;
  283. }
  284. }
  285. class AESGCMCipherBinding {
  286. constructor(config) {
  287. const enc = config.outbound;
  288. this.outSeqno = enc.seqno;
  289. this._onWrite = enc.onWrite;
  290. this._instance = new AESGCMCipher(enc.cipherInfo.sslName,
  291. enc.cipherKey,
  292. enc.cipherIV);
  293. this._dead = false;
  294. }
  295. free() {
  296. this._dead = true;
  297. this._instance.free();
  298. }
  299. allocPacket(payloadLen) {
  300. let pktLen = 4 + 1 + payloadLen;
  301. let padLen = 16 - ((pktLen - 4) & (16 - 1));
  302. if (padLen < 4)
  303. padLen += 16;
  304. pktLen += padLen;
  305. const packet = Buffer.allocUnsafe(pktLen + 16/* authTag */);
  306. writeUInt32BE(packet, pktLen - 4, 0);
  307. packet[4] = padLen;
  308. randomFillSync(packet, 5 + payloadLen, padLen);
  309. return packet;
  310. }
  311. encrypt(packet) {
  312. // `packet` === unencrypted packet
  313. if (this._dead)
  314. return;
  315. // Encrypts in-place
  316. this._instance.encrypt(packet);
  317. this._onWrite(packet);
  318. this.outSeqno = (this.outSeqno + 1) >>> 0;
  319. }
  320. }
  321. class GenericCipherNative {
  322. constructor(config) {
  323. const enc = config.outbound;
  324. this.outSeqno = enc.seqno;
  325. this._onWrite = enc.onWrite;
  326. this._encBlockLen = enc.cipherInfo.blockLen;
  327. this._cipherInstance = createCipheriv(enc.cipherInfo.sslName,
  328. enc.cipherKey,
  329. enc.cipherIV);
  330. this._macSSLName = enc.macInfo.sslName;
  331. this._macKey = enc.macKey;
  332. this._macActualLen = enc.macInfo.actualLen;
  333. this._macETM = enc.macInfo.isETM;
  334. this._aadLen = (this._macETM ? 4 : 0);
  335. this._dead = false;
  336. const discardLen = enc.cipherInfo.discardLen;
  337. if (discardLen) {
  338. let discard = DISCARD_CACHE.get(discardLen);
  339. if (discard === undefined) {
  340. discard = Buffer.alloc(discardLen);
  341. DISCARD_CACHE.set(discardLen, discard);
  342. }
  343. this._cipherInstance.update(discard);
  344. }
  345. }
  346. free() {
  347. this._dead = true;
  348. }
  349. allocPacket(payloadLen) {
  350. const blockLen = this._encBlockLen;
  351. let pktLen = 4 + 1 + payloadLen;
  352. let padLen = blockLen - ((pktLen - this._aadLen) & (blockLen - 1));
  353. if (padLen < 4)
  354. padLen += blockLen;
  355. pktLen += padLen;
  356. const packet = Buffer.allocUnsafe(pktLen);
  357. writeUInt32BE(packet, pktLen - 4, 0);
  358. packet[4] = padLen;
  359. randomFillSync(packet, 5 + payloadLen, padLen);
  360. return packet;
  361. }
  362. encrypt(packet) {
  363. // `packet` === unencrypted packet
  364. if (this._dead)
  365. return;
  366. let mac;
  367. if (this._macETM) {
  368. // Encrypt pad length, payload, and padding
  369. const lenBytes = new Uint8Array(packet.buffer, packet.byteOffset, 4);
  370. const encrypted = this._cipherInstance.update(
  371. new Uint8Array(packet.buffer,
  372. packet.byteOffset + 4,
  373. packet.length - 4)
  374. );
  375. this._onWrite(lenBytes);
  376. this._onWrite(encrypted);
  377. // TODO: look into storing seqno as 4-byte buffer and incrementing like we
  378. // do for AES-GCM IVs to avoid having to (re)write all 4 bytes every time
  379. mac = createHmac(this._macSSLName, this._macKey);
  380. writeUInt32BE(BUF_INT, this.outSeqno, 0);
  381. mac.update(BUF_INT);
  382. mac.update(lenBytes);
  383. mac.update(encrypted);
  384. } else {
  385. // Encrypt length field, pad length, payload, and padding
  386. const encrypted = this._cipherInstance.update(packet);
  387. this._onWrite(encrypted);
  388. // TODO: look into storing seqno as 4-byte buffer and incrementing like we
  389. // do for AES-GCM IVs to avoid having to (re)write all 4 bytes every time
  390. mac = createHmac(this._macSSLName, this._macKey);
  391. writeUInt32BE(BUF_INT, this.outSeqno, 0);
  392. mac.update(BUF_INT);
  393. mac.update(packet);
  394. }
  395. let digest = mac.digest();
  396. if (digest.length > this._macActualLen)
  397. digest = digest.slice(0, this._macActualLen);
  398. this._onWrite(digest);
  399. this.outSeqno = (this.outSeqno + 1) >>> 0;
  400. }
  401. }
  402. class GenericCipherBinding {
  403. constructor(config) {
  404. const enc = config.outbound;
  405. this.outSeqno = enc.seqno;
  406. this._onWrite = enc.onWrite;
  407. this._encBlockLen = enc.cipherInfo.blockLen;
  408. this._macLen = enc.macInfo.len;
  409. this._macActualLen = enc.macInfo.actualLen;
  410. this._aadLen = (enc.macInfo.isETM ? 4 : 0);
  411. this._instance = new GenericCipher(enc.cipherInfo.sslName,
  412. enc.cipherKey,
  413. enc.cipherIV,
  414. enc.macInfo.sslName,
  415. enc.macKey,
  416. enc.macInfo.isETM);
  417. this._dead = false;
  418. }
  419. free() {
  420. this._dead = true;
  421. this._instance.free();
  422. }
  423. allocPacket(payloadLen) {
  424. const blockLen = this._encBlockLen;
  425. let pktLen = 4 + 1 + payloadLen;
  426. let padLen = blockLen - ((pktLen - this._aadLen) & (blockLen - 1));
  427. if (padLen < 4)
  428. padLen += blockLen;
  429. pktLen += padLen;
  430. const packet = Buffer.allocUnsafe(pktLen + this._macLen);
  431. writeUInt32BE(packet, pktLen - 4, 0);
  432. packet[4] = padLen;
  433. randomFillSync(packet, 5 + payloadLen, padLen);
  434. return packet;
  435. }
  436. encrypt(packet) {
  437. // `packet` === unencrypted packet
  438. if (this._dead)
  439. return;
  440. // Encrypts in-place
  441. this._instance.encrypt(packet, this.outSeqno);
  442. if (this._macActualLen < this._macLen) {
  443. packet = new FastBuffer(packet.buffer,
  444. packet.byteOffset,
  445. (packet.length
  446. - (this._macLen - this._macActualLen)));
  447. }
  448. this._onWrite(packet);
  449. this.outSeqno = (this.outSeqno + 1) >>> 0;
  450. }
  451. }
  452. class NullDecipher {
  453. constructor(seqno, onPayload) {
  454. this.inSeqno = seqno;
  455. this._onPayload = onPayload;
  456. this._len = 0;
  457. this._lenBytes = 0;
  458. this._packet = null;
  459. this._packetPos = 0;
  460. }
  461. free() {}
  462. decrypt(data, p, dataLen) {
  463. while (p < dataLen) {
  464. // Read packet length
  465. if (this._lenBytes < 4) {
  466. let nb = Math.min(4 - this._lenBytes, dataLen - p);
  467. this._lenBytes += nb;
  468. while (nb--)
  469. this._len = (this._len << 8) + data[p++];
  470. if (this._lenBytes < 4)
  471. return;
  472. if (this._len > MAX_PACKET_SIZE
  473. || this._len < 8
  474. || (4 + this._len & 7) !== 0) {
  475. throw new Error('Bad packet length');
  476. }
  477. if (p >= dataLen)
  478. return;
  479. }
  480. // Read padding length, payload, and padding
  481. if (this._packetPos < this._len) {
  482. const nb = Math.min(this._len - this._packetPos, dataLen - p);
  483. if (p !== 0 || nb !== dataLen) {
  484. if (nb === this._len) {
  485. this._packet = new FastBuffer(data.buffer, data.byteOffset + p, nb);
  486. } else {
  487. this._packet = Buffer.allocUnsafe(this._len);
  488. this._packet.set(
  489. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  490. this._packetPos
  491. );
  492. }
  493. } else if (nb === this._len) {
  494. this._packet = data;
  495. } else {
  496. if (!this._packet)
  497. this._packet = Buffer.allocUnsafe(this._len);
  498. this._packet.set(data, this._packetPos);
  499. }
  500. p += nb;
  501. this._packetPos += nb;
  502. if (this._packetPos < this._len)
  503. return;
  504. }
  505. const payload = (!this._packet
  506. ? EMPTY_BUFFER
  507. : new FastBuffer(this._packet.buffer,
  508. this._packet.byteOffset + 1,
  509. this._packet.length
  510. - this._packet[0] - 1));
  511. // Prepare for next packet
  512. this.inSeqno = (this.inSeqno + 1) >>> 0;
  513. this._len = 0;
  514. this._lenBytes = 0;
  515. this._packet = null;
  516. this._packetPos = 0;
  517. {
  518. const ret = this._onPayload(payload);
  519. if (ret !== undefined)
  520. return (ret === false ? p : ret);
  521. }
  522. }
  523. }
  524. }
  525. class ChaChaPolyDecipherNative {
  526. constructor(config) {
  527. const dec = config.inbound;
  528. this.inSeqno = dec.seqno;
  529. this._onPayload = dec.onPayload;
  530. this._decKeyMain = dec.decipherKey.slice(0, 32);
  531. this._decKeyPktLen = dec.decipherKey.slice(32);
  532. this._len = 0;
  533. this._lenBuf = Buffer.alloc(4);
  534. this._lenPos = 0;
  535. this._packet = null;
  536. this._pktLen = 0;
  537. this._mac = Buffer.allocUnsafe(16);
  538. this._calcMac = Buffer.allocUnsafe(16);
  539. this._macPos = 0;
  540. }
  541. free() {}
  542. decrypt(data, p, dataLen) {
  543. // `data` === encrypted data
  544. while (p < dataLen) {
  545. // Read packet length
  546. if (this._lenPos < 4) {
  547. let nb = Math.min(4 - this._lenPos, dataLen - p);
  548. while (nb--)
  549. this._lenBuf[this._lenPos++] = data[p++];
  550. if (this._lenPos < 4)
  551. return;
  552. POLY1305_OUT_COMPUTE[0] = 0; // Set counter to 0 (little endian)
  553. writeUInt32BE(POLY1305_OUT_COMPUTE, this.inSeqno, 12);
  554. const decLenBytes =
  555. createDecipheriv('chacha20', this._decKeyPktLen, POLY1305_OUT_COMPUTE)
  556. .update(this._lenBuf);
  557. this._len = readUInt32BE(decLenBytes, 0);
  558. if (this._len > MAX_PACKET_SIZE
  559. || this._len < 8
  560. || (this._len & 7) !== 0) {
  561. throw new Error('Bad packet length');
  562. }
  563. }
  564. // Read padding length, payload, and padding
  565. if (this._pktLen < this._len) {
  566. if (p >= dataLen)
  567. return;
  568. const nb = Math.min(this._len - this._pktLen, dataLen - p);
  569. let encrypted;
  570. if (p !== 0 || nb !== dataLen)
  571. encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb);
  572. else
  573. encrypted = data;
  574. if (nb === this._len) {
  575. this._packet = encrypted;
  576. } else {
  577. if (!this._packet)
  578. this._packet = Buffer.allocUnsafe(this._len);
  579. this._packet.set(encrypted, this._pktLen);
  580. }
  581. p += nb;
  582. this._pktLen += nb;
  583. if (this._pktLen < this._len || p >= dataLen)
  584. return;
  585. }
  586. // Read Poly1305 MAC
  587. {
  588. const nb = Math.min(16 - this._macPos, dataLen - p);
  589. // TODO: avoid copying if entire MAC is in current chunk
  590. if (p !== 0 || nb !== dataLen) {
  591. this._mac.set(
  592. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  593. this._macPos
  594. );
  595. } else {
  596. this._mac.set(data, this._macPos);
  597. }
  598. p += nb;
  599. this._macPos += nb;
  600. if (this._macPos < 16)
  601. return;
  602. }
  603. // Generate Poly1305 key
  604. POLY1305_OUT_COMPUTE[0] = 0; // Set counter to 0 (little endian)
  605. writeUInt32BE(POLY1305_OUT_COMPUTE, this.inSeqno, 12);
  606. const polyKey =
  607. createCipheriv('chacha20', this._decKeyMain, POLY1305_OUT_COMPUTE)
  608. .update(POLY1305_ZEROS);
  609. // Calculate and compare Poly1305 MACs
  610. poly1305_auth(POLY1305_RESULT_MALLOC,
  611. this._lenBuf,
  612. 4,
  613. this._packet,
  614. this._packet.length,
  615. polyKey);
  616. this._calcMac.set(
  617. new Uint8Array(POLY1305_WASM_MODULE.HEAPU8.buffer,
  618. POLY1305_RESULT_MALLOC,
  619. 16),
  620. 0
  621. );
  622. if (!timingSafeEqual(this._calcMac, this._mac))
  623. throw new Error('Invalid MAC');
  624. // Decrypt packet
  625. POLY1305_OUT_COMPUTE[0] = 1; // Set counter to 1 (little endian)
  626. const packet =
  627. createDecipheriv('chacha20', this._decKeyMain, POLY1305_OUT_COMPUTE)
  628. .update(this._packet);
  629. const payload = new FastBuffer(packet.buffer,
  630. packet.byteOffset + 1,
  631. packet.length - packet[0] - 1);
  632. // Prepare for next packet
  633. this.inSeqno = (this.inSeqno + 1) >>> 0;
  634. this._len = 0;
  635. this._lenPos = 0;
  636. this._packet = null;
  637. this._pktLen = 0;
  638. this._macPos = 0;
  639. {
  640. const ret = this._onPayload(payload);
  641. if (ret !== undefined)
  642. return (ret === false ? p : ret);
  643. }
  644. }
  645. }
  646. }
  647. class ChaChaPolyDecipherBinding {
  648. constructor(config) {
  649. const dec = config.inbound;
  650. this.inSeqno = dec.seqno;
  651. this._onPayload = dec.onPayload;
  652. this._instance = new ChaChaPolyDecipher(dec.decipherKey);
  653. this._len = 0;
  654. this._lenBuf = Buffer.alloc(4);
  655. this._lenPos = 0;
  656. this._packet = null;
  657. this._pktLen = 0;
  658. this._mac = Buffer.allocUnsafe(16);
  659. this._macPos = 0;
  660. }
  661. free() {
  662. this._instance.free();
  663. }
  664. decrypt(data, p, dataLen) {
  665. // `data` === encrypted data
  666. while (p < dataLen) {
  667. // Read packet length
  668. if (this._lenPos < 4) {
  669. let nb = Math.min(4 - this._lenPos, dataLen - p);
  670. while (nb--)
  671. this._lenBuf[this._lenPos++] = data[p++];
  672. if (this._lenPos < 4)
  673. return;
  674. this._len = this._instance.decryptLen(this._lenBuf, this.inSeqno);
  675. if (this._len > MAX_PACKET_SIZE
  676. || this._len < 8
  677. || (this._len & 7) !== 0) {
  678. throw new Error('Bad packet length');
  679. }
  680. if (p >= dataLen)
  681. return;
  682. }
  683. // Read padding length, payload, and padding
  684. if (this._pktLen < this._len) {
  685. const nb = Math.min(this._len - this._pktLen, dataLen - p);
  686. let encrypted;
  687. if (p !== 0 || nb !== dataLen)
  688. encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb);
  689. else
  690. encrypted = data;
  691. if (nb === this._len) {
  692. this._packet = encrypted;
  693. } else {
  694. if (!this._packet)
  695. this._packet = Buffer.allocUnsafe(this._len);
  696. this._packet.set(encrypted, this._pktLen);
  697. }
  698. p += nb;
  699. this._pktLen += nb;
  700. if (this._pktLen < this._len || p >= dataLen)
  701. return;
  702. }
  703. // Read Poly1305 MAC
  704. {
  705. const nb = Math.min(16 - this._macPos, dataLen - p);
  706. // TODO: avoid copying if entire MAC is in current chunk
  707. if (p !== 0 || nb !== dataLen) {
  708. this._mac.set(
  709. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  710. this._macPos
  711. );
  712. } else {
  713. this._mac.set(data, this._macPos);
  714. }
  715. p += nb;
  716. this._macPos += nb;
  717. if (this._macPos < 16)
  718. return;
  719. }
  720. this._instance.decrypt(this._packet, this._mac, this.inSeqno);
  721. const payload = new FastBuffer(this._packet.buffer,
  722. this._packet.byteOffset + 1,
  723. this._packet.length - this._packet[0] - 1);
  724. // Prepare for next packet
  725. this.inSeqno = (this.inSeqno + 1) >>> 0;
  726. this._len = 0;
  727. this._lenPos = 0;
  728. this._packet = null;
  729. this._pktLen = 0;
  730. this._macPos = 0;
  731. {
  732. const ret = this._onPayload(payload);
  733. if (ret !== undefined)
  734. return (ret === false ? p : ret);
  735. }
  736. }
  737. }
  738. }
  739. class AESGCMDecipherNative {
  740. constructor(config) {
  741. const dec = config.inbound;
  742. this.inSeqno = dec.seqno;
  743. this._onPayload = dec.onPayload;
  744. this._decipherInstance = null;
  745. this._decipherSSLName = dec.decipherInfo.sslName;
  746. this._decipherKey = dec.decipherKey;
  747. this._decipherIV = dec.decipherIV;
  748. this._len = 0;
  749. this._lenBytes = 0;
  750. this._packet = null;
  751. this._packetPos = 0;
  752. this._pktLen = 0;
  753. this._tag = Buffer.allocUnsafe(16);
  754. this._tagPos = 0;
  755. }
  756. free() {}
  757. decrypt(data, p, dataLen) {
  758. // `data` === encrypted data
  759. while (p < dataLen) {
  760. // Read packet length (unencrypted, but AAD)
  761. if (this._lenBytes < 4) {
  762. let nb = Math.min(4 - this._lenBytes, dataLen - p);
  763. this._lenBytes += nb;
  764. while (nb--)
  765. this._len = (this._len << 8) + data[p++];
  766. if (this._lenBytes < 4)
  767. return;
  768. if ((this._len + 20) > MAX_PACKET_SIZE
  769. || this._len < 16
  770. || (this._len & 15) !== 0) {
  771. throw new Error('Bad packet length');
  772. }
  773. this._decipherInstance = createDecipheriv(
  774. this._decipherSSLName,
  775. this._decipherKey,
  776. this._decipherIV
  777. );
  778. this._decipherInstance.setAutoPadding(false);
  779. this._decipherInstance.setAAD(intToBytes(this._len));
  780. }
  781. // Read padding length, payload, and padding
  782. if (this._pktLen < this._len) {
  783. if (p >= dataLen)
  784. return;
  785. const nb = Math.min(this._len - this._pktLen, dataLen - p);
  786. let decrypted;
  787. if (p !== 0 || nb !== dataLen) {
  788. decrypted = this._decipherInstance.update(
  789. new Uint8Array(data.buffer, data.byteOffset + p, nb)
  790. );
  791. } else {
  792. decrypted = this._decipherInstance.update(data);
  793. }
  794. if (decrypted.length) {
  795. if (nb === this._len) {
  796. this._packet = decrypted;
  797. } else {
  798. if (!this._packet)
  799. this._packet = Buffer.allocUnsafe(this._len);
  800. this._packet.set(decrypted, this._packetPos);
  801. }
  802. this._packetPos += decrypted.length;
  803. }
  804. p += nb;
  805. this._pktLen += nb;
  806. if (this._pktLen < this._len || p >= dataLen)
  807. return;
  808. }
  809. // Read authentication tag
  810. {
  811. const nb = Math.min(16 - this._tagPos, dataLen - p);
  812. if (p !== 0 || nb !== dataLen) {
  813. this._tag.set(
  814. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  815. this._tagPos
  816. );
  817. } else {
  818. this._tag.set(data, this._tagPos);
  819. }
  820. p += nb;
  821. this._tagPos += nb;
  822. if (this._tagPos < 16)
  823. return;
  824. }
  825. {
  826. // Verify authentication tag
  827. this._decipherInstance.setAuthTag(this._tag);
  828. const decrypted = this._decipherInstance.final();
  829. // XXX: this should never output any data since stream ciphers always
  830. // return data from .update() and block ciphers must end on a multiple
  831. // of the block length, which would have caused an exception to be
  832. // thrown if the total input was not...
  833. if (decrypted.length) {
  834. if (this._packet)
  835. this._packet.set(decrypted, this._packetPos);
  836. else
  837. this._packet = decrypted;
  838. }
  839. }
  840. const payload = (!this._packet
  841. ? EMPTY_BUFFER
  842. : new FastBuffer(this._packet.buffer,
  843. this._packet.byteOffset + 1,
  844. this._packet.length
  845. - this._packet[0] - 1));
  846. // Prepare for next packet
  847. this.inSeqno = (this.inSeqno + 1) >>> 0;
  848. ivIncrement(this._decipherIV);
  849. this._len = 0;
  850. this._lenBytes = 0;
  851. this._packet = null;
  852. this._packetPos = 0;
  853. this._pktLen = 0;
  854. this._tagPos = 0;
  855. {
  856. const ret = this._onPayload(payload);
  857. if (ret !== undefined)
  858. return (ret === false ? p : ret);
  859. }
  860. }
  861. }
  862. }
  863. class AESGCMDecipherBinding {
  864. constructor(config) {
  865. const dec = config.inbound;
  866. this.inSeqno = dec.seqno;
  867. this._onPayload = dec.onPayload;
  868. this._instance = new AESGCMDecipher(dec.decipherInfo.sslName,
  869. dec.decipherKey,
  870. dec.decipherIV);
  871. this._len = 0;
  872. this._lenBytes = 0;
  873. this._packet = null;
  874. this._pktLen = 0;
  875. this._tag = Buffer.allocUnsafe(16);
  876. this._tagPos = 0;
  877. }
  878. free() {}
  879. decrypt(data, p, dataLen) {
  880. // `data` === encrypted data
  881. while (p < dataLen) {
  882. // Read packet length (unencrypted, but AAD)
  883. if (this._lenBytes < 4) {
  884. let nb = Math.min(4 - this._lenBytes, dataLen - p);
  885. this._lenBytes += nb;
  886. while (nb--)
  887. this._len = (this._len << 8) + data[p++];
  888. if (this._lenBytes < 4)
  889. return;
  890. if ((this._len + 20) > MAX_PACKET_SIZE
  891. || this._len < 16
  892. || (this._len & 15) !== 0) {
  893. throw new Error(`Bad packet length: ${this._len}`);
  894. }
  895. }
  896. // Read padding length, payload, and padding
  897. if (this._pktLen < this._len) {
  898. if (p >= dataLen)
  899. return;
  900. const nb = Math.min(this._len - this._pktLen, dataLen - p);
  901. let encrypted;
  902. if (p !== 0 || nb !== dataLen)
  903. encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb);
  904. else
  905. encrypted = data;
  906. if (nb === this._len) {
  907. this._packet = encrypted;
  908. } else {
  909. if (!this._packet)
  910. this._packet = Buffer.allocUnsafe(this._len);
  911. this._packet.set(encrypted, this._pktLen);
  912. }
  913. p += nb;
  914. this._pktLen += nb;
  915. if (this._pktLen < this._len || p >= dataLen)
  916. return;
  917. }
  918. // Read authentication tag
  919. {
  920. const nb = Math.min(16 - this._tagPos, dataLen - p);
  921. if (p !== 0 || nb !== dataLen) {
  922. this._tag.set(
  923. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  924. this._tagPos
  925. );
  926. } else {
  927. this._tag.set(data, this._tagPos);
  928. }
  929. p += nb;
  930. this._tagPos += nb;
  931. if (this._tagPos < 16)
  932. return;
  933. }
  934. this._instance.decrypt(this._packet, this._len, this._tag);
  935. const payload = new FastBuffer(this._packet.buffer,
  936. this._packet.byteOffset + 1,
  937. this._packet.length - this._packet[0] - 1);
  938. // Prepare for next packet
  939. this.inSeqno = (this.inSeqno + 1) >>> 0;
  940. this._len = 0;
  941. this._lenBytes = 0;
  942. this._packet = null;
  943. this._pktLen = 0;
  944. this._tagPos = 0;
  945. {
  946. const ret = this._onPayload(payload);
  947. if (ret !== undefined)
  948. return (ret === false ? p : ret);
  949. }
  950. }
  951. }
  952. }
  953. // TODO: test incremental .update()s vs. copying to _packet and doing a single
  954. // .update() after entire packet read -- a single .update() would allow
  955. // verifying MAC before decrypting for ETM MACs
  956. class GenericDecipherNative {
  957. constructor(config) {
  958. const dec = config.inbound;
  959. this.inSeqno = dec.seqno;
  960. this._onPayload = dec.onPayload;
  961. this._decipherInstance = createDecipheriv(dec.decipherInfo.sslName,
  962. dec.decipherKey,
  963. dec.decipherIV);
  964. this._decipherInstance.setAutoPadding(false);
  965. this._block = Buffer.allocUnsafe(
  966. dec.macInfo.isETM ? 4 : dec.decipherInfo.blockLen
  967. );
  968. this._blockSize = dec.decipherInfo.blockLen;
  969. this._blockPos = 0;
  970. this._len = 0;
  971. this._packet = null;
  972. this._packetPos = 0;
  973. this._pktLen = 0;
  974. this._mac = Buffer.allocUnsafe(dec.macInfo.actualLen);
  975. this._macPos = 0;
  976. this._macSSLName = dec.macInfo.sslName;
  977. this._macKey = dec.macKey;
  978. this._macActualLen = dec.macInfo.actualLen;
  979. this._macETM = dec.macInfo.isETM;
  980. this._macInstance = null;
  981. const discardLen = dec.decipherInfo.discardLen;
  982. if (discardLen) {
  983. let discard = DISCARD_CACHE.get(discardLen);
  984. if (discard === undefined) {
  985. discard = Buffer.alloc(discardLen);
  986. DISCARD_CACHE.set(discardLen, discard);
  987. }
  988. this._decipherInstance.update(discard);
  989. }
  990. }
  991. free() {}
  992. decrypt(data, p, dataLen) {
  993. // `data` === encrypted data
  994. while (p < dataLen) {
  995. // Read first encrypted block
  996. if (this._blockPos < this._block.length) {
  997. const nb = Math.min(this._block.length - this._blockPos, dataLen - p);
  998. if (p !== 0 || nb !== dataLen || nb < data.length) {
  999. this._block.set(
  1000. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  1001. this._blockPos
  1002. );
  1003. } else {
  1004. this._block.set(data, this._blockPos);
  1005. }
  1006. p += nb;
  1007. this._blockPos += nb;
  1008. if (this._blockPos < this._block.length)
  1009. return;
  1010. let decrypted;
  1011. let need;
  1012. if (this._macETM) {
  1013. this._len = need = readUInt32BE(this._block, 0);
  1014. } else {
  1015. // Decrypt first block to get packet length
  1016. decrypted = this._decipherInstance.update(this._block);
  1017. this._len = readUInt32BE(decrypted, 0);
  1018. need = 4 + this._len - this._blockSize;
  1019. }
  1020. if (this._len > MAX_PACKET_SIZE
  1021. || this._len < 5
  1022. || (need & (this._blockSize - 1)) !== 0) {
  1023. throw new Error('Bad packet length');
  1024. }
  1025. // Create MAC up front to calculate in parallel with decryption
  1026. this._macInstance = createHmac(this._macSSLName, this._macKey);
  1027. writeUInt32BE(BUF_INT, this.inSeqno, 0);
  1028. this._macInstance.update(BUF_INT);
  1029. if (this._macETM) {
  1030. this._macInstance.update(this._block);
  1031. } else {
  1032. this._macInstance.update(new Uint8Array(decrypted.buffer,
  1033. decrypted.byteOffset,
  1034. 4));
  1035. this._pktLen = decrypted.length - 4;
  1036. this._packetPos = this._pktLen;
  1037. this._packet = Buffer.allocUnsafe(this._len);
  1038. this._packet.set(
  1039. new Uint8Array(decrypted.buffer,
  1040. decrypted.byteOffset + 4,
  1041. this._packetPos),
  1042. 0
  1043. );
  1044. }
  1045. if (p >= dataLen)
  1046. return;
  1047. }
  1048. // Read padding length, payload, and padding
  1049. if (this._pktLen < this._len) {
  1050. const nb = Math.min(this._len - this._pktLen, dataLen - p);
  1051. let encrypted;
  1052. if (p !== 0 || nb !== dataLen)
  1053. encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb);
  1054. else
  1055. encrypted = data;
  1056. if (this._macETM)
  1057. this._macInstance.update(encrypted);
  1058. const decrypted = this._decipherInstance.update(encrypted);
  1059. if (decrypted.length) {
  1060. if (nb === this._len) {
  1061. this._packet = decrypted;
  1062. } else {
  1063. if (!this._packet)
  1064. this._packet = Buffer.allocUnsafe(this._len);
  1065. this._packet.set(decrypted, this._packetPos);
  1066. }
  1067. this._packetPos += decrypted.length;
  1068. }
  1069. p += nb;
  1070. this._pktLen += nb;
  1071. if (this._pktLen < this._len || p >= dataLen)
  1072. return;
  1073. }
  1074. // Read MAC
  1075. {
  1076. const nb = Math.min(this._macActualLen - this._macPos, dataLen - p);
  1077. if (p !== 0 || nb !== dataLen) {
  1078. this._mac.set(
  1079. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  1080. this._macPos
  1081. );
  1082. } else {
  1083. this._mac.set(data, this._macPos);
  1084. }
  1085. p += nb;
  1086. this._macPos += nb;
  1087. if (this._macPos < this._macActualLen)
  1088. return;
  1089. }
  1090. // Verify MAC
  1091. if (!this._macETM)
  1092. this._macInstance.update(this._packet);
  1093. let calculated = this._macInstance.digest();
  1094. if (this._macActualLen < calculated.length) {
  1095. calculated = new Uint8Array(calculated.buffer,
  1096. calculated.byteOffset,
  1097. this._macActualLen);
  1098. }
  1099. if (!timingSafeEquals(calculated, this._mac))
  1100. throw new Error('Invalid MAC');
  1101. const payload = new FastBuffer(this._packet.buffer,
  1102. this._packet.byteOffset + 1,
  1103. this._packet.length - this._packet[0] - 1);
  1104. // Prepare for next packet
  1105. this.inSeqno = (this.inSeqno + 1) >>> 0;
  1106. this._blockPos = 0;
  1107. this._len = 0;
  1108. this._packet = null;
  1109. this._packetPos = 0;
  1110. this._pktLen = 0;
  1111. this._macPos = 0;
  1112. this._macInstance = null;
  1113. {
  1114. const ret = this._onPayload(payload);
  1115. if (ret !== undefined)
  1116. return (ret === false ? p : ret);
  1117. }
  1118. }
  1119. }
  1120. }
  1121. class GenericDecipherBinding {
  1122. constructor(config) {
  1123. const dec = config.inbound;
  1124. this.inSeqno = dec.seqno;
  1125. this._onPayload = dec.onPayload;
  1126. this._instance = new GenericDecipher(dec.decipherInfo.sslName,
  1127. dec.decipherKey,
  1128. dec.decipherIV,
  1129. dec.macInfo.sslName,
  1130. dec.macKey,
  1131. dec.macInfo.isETM,
  1132. dec.macInfo.actualLen);
  1133. this._block = Buffer.allocUnsafe(
  1134. dec.macInfo.isETM || dec.decipherInfo.stream
  1135. ? 4
  1136. : dec.decipherInfo.blockLen
  1137. );
  1138. this._blockPos = 0;
  1139. this._len = 0;
  1140. this._packet = null;
  1141. this._pktLen = 0;
  1142. this._mac = Buffer.allocUnsafe(dec.macInfo.actualLen);
  1143. this._macPos = 0;
  1144. this._macActualLen = dec.macInfo.actualLen;
  1145. this._macETM = dec.macInfo.isETM;
  1146. }
  1147. free() {
  1148. this._instance.free();
  1149. }
  1150. decrypt(data, p, dataLen) {
  1151. // `data` === encrypted data
  1152. while (p < dataLen) {
  1153. // Read first encrypted block
  1154. if (this._blockPos < this._block.length) {
  1155. const nb = Math.min(this._block.length - this._blockPos, dataLen - p);
  1156. if (p !== 0 || nb !== dataLen || nb < data.length) {
  1157. this._block.set(
  1158. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  1159. this._blockPos
  1160. );
  1161. } else {
  1162. this._block.set(data, this._blockPos);
  1163. }
  1164. p += nb;
  1165. this._blockPos += nb;
  1166. if (this._blockPos < this._block.length)
  1167. return;
  1168. let need;
  1169. if (this._macETM) {
  1170. this._len = need = readUInt32BE(this._block, 0);
  1171. } else {
  1172. // Decrypt first block to get packet length
  1173. this._instance.decryptBlock(this._block);
  1174. this._len = readUInt32BE(this._block, 0);
  1175. need = 4 + this._len - this._block.length;
  1176. }
  1177. if (this._len > MAX_PACKET_SIZE
  1178. || this._len < 5
  1179. || (need & (this._block.length - 1)) !== 0) {
  1180. throw new Error('Bad packet length');
  1181. }
  1182. if (!this._macETM) {
  1183. this._pktLen = (this._block.length - 4);
  1184. if (this._pktLen) {
  1185. this._packet = Buffer.allocUnsafe(this._len);
  1186. this._packet.set(
  1187. new Uint8Array(this._block.buffer,
  1188. this._block.byteOffset + 4,
  1189. this._pktLen),
  1190. 0
  1191. );
  1192. }
  1193. }
  1194. if (p >= dataLen)
  1195. return;
  1196. }
  1197. // Read padding length, payload, and padding
  1198. if (this._pktLen < this._len) {
  1199. const nb = Math.min(this._len - this._pktLen, dataLen - p);
  1200. let encrypted;
  1201. if (p !== 0 || nb !== dataLen)
  1202. encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb);
  1203. else
  1204. encrypted = data;
  1205. if (nb === this._len) {
  1206. this._packet = encrypted;
  1207. } else {
  1208. if (!this._packet)
  1209. this._packet = Buffer.allocUnsafe(this._len);
  1210. this._packet.set(encrypted, this._pktLen);
  1211. }
  1212. p += nb;
  1213. this._pktLen += nb;
  1214. if (this._pktLen < this._len || p >= dataLen)
  1215. return;
  1216. }
  1217. // Read MAC
  1218. {
  1219. const nb = Math.min(this._macActualLen - this._macPos, dataLen - p);
  1220. if (p !== 0 || nb !== dataLen) {
  1221. this._mac.set(
  1222. new Uint8Array(data.buffer, data.byteOffset + p, nb),
  1223. this._macPos
  1224. );
  1225. } else {
  1226. this._mac.set(data, this._macPos);
  1227. }
  1228. p += nb;
  1229. this._macPos += nb;
  1230. if (this._macPos < this._macActualLen)
  1231. return;
  1232. }
  1233. // Decrypt and verify MAC
  1234. this._instance.decrypt(this._packet,
  1235. this.inSeqno,
  1236. this._block,
  1237. this._mac);
  1238. const payload = new FastBuffer(this._packet.buffer,
  1239. this._packet.byteOffset + 1,
  1240. this._packet.length - this._packet[0] - 1);
  1241. // Prepare for next packet
  1242. this.inSeqno = (this.inSeqno + 1) >>> 0;
  1243. this._blockPos = 0;
  1244. this._len = 0;
  1245. this._packet = null;
  1246. this._pktLen = 0;
  1247. this._macPos = 0;
  1248. this._macInstance = null;
  1249. {
  1250. const ret = this._onPayload(payload);
  1251. if (ret !== undefined)
  1252. return (ret === false ? p : ret);
  1253. }
  1254. }
  1255. }
  1256. }
  1257. // Increments unsigned, big endian counter (last 8 bytes) of AES-GCM IV
  1258. function ivIncrement(iv) {
  1259. // eslint-disable-next-line no-unused-expressions
  1260. ++iv[11] >>> 8
  1261. && ++iv[10] >>> 8
  1262. && ++iv[9] >>> 8
  1263. && ++iv[8] >>> 8
  1264. && ++iv[7] >>> 8
  1265. && ++iv[6] >>> 8
  1266. && ++iv[5] >>> 8
  1267. && ++iv[4] >>> 8;
  1268. }
  1269. const intToBytes = (() => {
  1270. const ret = Buffer.alloc(4);
  1271. return (n) => {
  1272. ret[0] = (n >>> 24);
  1273. ret[1] = (n >>> 16);
  1274. ret[2] = (n >>> 8);
  1275. ret[3] = n;
  1276. return ret;
  1277. };
  1278. })();
  1279. function timingSafeEquals(a, b) {
  1280. if (a.length !== b.length) {
  1281. timingSafeEqual(a, a);
  1282. return false;
  1283. }
  1284. return timingSafeEqual(a, b);
  1285. }
  1286. function createCipher(config) {
  1287. if (typeof config !== 'object' || config === null)
  1288. throw new Error('Invalid config');
  1289. if (typeof config.outbound !== 'object' || config.outbound === null)
  1290. throw new Error('Invalid outbound');
  1291. const outbound = config.outbound;
  1292. if (typeof outbound.onWrite !== 'function')
  1293. throw new Error('Invalid outbound.onWrite');
  1294. if (typeof outbound.cipherInfo !== 'object' || outbound.cipherInfo === null)
  1295. throw new Error('Invalid outbound.cipherInfo');
  1296. if (!Buffer.isBuffer(outbound.cipherKey)
  1297. || outbound.cipherKey.length !== outbound.cipherInfo.keyLen) {
  1298. throw new Error('Invalid outbound.cipherKey');
  1299. }
  1300. if (outbound.cipherInfo.ivLen
  1301. && (!Buffer.isBuffer(outbound.cipherIV)
  1302. || outbound.cipherIV.length !== outbound.cipherInfo.ivLen)) {
  1303. throw new Error('Invalid outbound.cipherIV');
  1304. }
  1305. if (typeof outbound.seqno !== 'number'
  1306. || outbound.seqno < 0
  1307. || outbound.seqno > MAX_SEQNO) {
  1308. throw new Error('Invalid outbound.seqno');
  1309. }
  1310. const forceNative = !!outbound.forceNative;
  1311. switch (outbound.cipherInfo.sslName) {
  1312. case 'aes-128-gcm':
  1313. case 'aes-256-gcm':
  1314. return (AESGCMCipher && !forceNative
  1315. ? new AESGCMCipherBinding(config)
  1316. : new AESGCMCipherNative(config));
  1317. case 'chacha20':
  1318. return (ChaChaPolyCipher && !forceNative
  1319. ? new ChaChaPolyCipherBinding(config)
  1320. : new ChaChaPolyCipherNative(config));
  1321. default: {
  1322. if (typeof outbound.macInfo !== 'object' || outbound.macInfo === null)
  1323. throw new Error('Invalid outbound.macInfo');
  1324. if (!Buffer.isBuffer(outbound.macKey)
  1325. || outbound.macKey.length !== outbound.macInfo.len) {
  1326. throw new Error('Invalid outbound.macKey');
  1327. }
  1328. return (GenericCipher && !forceNative
  1329. ? new GenericCipherBinding(config)
  1330. : new GenericCipherNative(config));
  1331. }
  1332. }
  1333. }
  1334. function createDecipher(config) {
  1335. if (typeof config !== 'object' || config === null)
  1336. throw new Error('Invalid config');
  1337. if (typeof config.inbound !== 'object' || config.inbound === null)
  1338. throw new Error('Invalid inbound');
  1339. const inbound = config.inbound;
  1340. if (typeof inbound.onPayload !== 'function')
  1341. throw new Error('Invalid inbound.onPayload');
  1342. if (typeof inbound.decipherInfo !== 'object'
  1343. || inbound.decipherInfo === null) {
  1344. throw new Error('Invalid inbound.decipherInfo');
  1345. }
  1346. if (!Buffer.isBuffer(inbound.decipherKey)
  1347. || inbound.decipherKey.length !== inbound.decipherInfo.keyLen) {
  1348. throw new Error('Invalid inbound.decipherKey');
  1349. }
  1350. if (inbound.decipherInfo.ivLen
  1351. && (!Buffer.isBuffer(inbound.decipherIV)
  1352. || inbound.decipherIV.length !== inbound.decipherInfo.ivLen)) {
  1353. throw new Error('Invalid inbound.decipherIV');
  1354. }
  1355. if (typeof inbound.seqno !== 'number'
  1356. || inbound.seqno < 0
  1357. || inbound.seqno > MAX_SEQNO) {
  1358. throw new Error('Invalid inbound.seqno');
  1359. }
  1360. const forceNative = !!inbound.forceNative;
  1361. switch (inbound.decipherInfo.sslName) {
  1362. case 'aes-128-gcm':
  1363. case 'aes-256-gcm':
  1364. return (AESGCMDecipher && !forceNative
  1365. ? new AESGCMDecipherBinding(config)
  1366. : new AESGCMDecipherNative(config));
  1367. case 'chacha20':
  1368. return (ChaChaPolyDecipher && !forceNative
  1369. ? new ChaChaPolyDecipherBinding(config)
  1370. : new ChaChaPolyDecipherNative(config));
  1371. default: {
  1372. if (typeof inbound.macInfo !== 'object' || inbound.macInfo === null)
  1373. throw new Error('Invalid inbound.macInfo');
  1374. if (!Buffer.isBuffer(inbound.macKey)
  1375. || inbound.macKey.length !== inbound.macInfo.len) {
  1376. throw new Error('Invalid inbound.macKey');
  1377. }
  1378. return (GenericDecipher && !forceNative
  1379. ? new GenericDecipherBinding(config)
  1380. : new GenericDecipherNative(config));
  1381. }
  1382. }
  1383. }
  1384. module.exports = {
  1385. CIPHER_INFO,
  1386. MAC_INFO,
  1387. bindingAvailable: !!binding,
  1388. init: (() => {
  1389. // eslint-disable-next-line no-async-promise-executor
  1390. return new Promise(async (resolve, reject) => {
  1391. try {
  1392. POLY1305_WASM_MODULE = await require('./crypto/poly1305.js')();
  1393. POLY1305_RESULT_MALLOC = POLY1305_WASM_MODULE._malloc(16);
  1394. poly1305_auth = POLY1305_WASM_MODULE.cwrap(
  1395. 'poly1305_auth',
  1396. null,
  1397. ['number', 'array', 'number', 'array', 'number', 'array']
  1398. );
  1399. } catch (ex) {
  1400. return reject(ex);
  1401. }
  1402. resolve();
  1403. });
  1404. })(),
  1405. NullCipher,
  1406. createCipher,
  1407. NullDecipher,
  1408. createDecipher,
  1409. };