werift 0.22.9 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/lib/dtls/src/flight/server/flight6.js +12 -2
  2. package/lib/dtls/src/flight/server/flight6.js.map +1 -1
  3. package/lib/dtls/src/server.js +6 -1
  4. package/lib/dtls/src/server.js.map +1 -1
  5. package/lib/dtls/src/socket.d.ts +1 -0
  6. package/lib/dtls/src/socket.js +3 -0
  7. package/lib/dtls/src/socket.js.map +1 -1
  8. package/lib/index.mjs +434 -75
  9. package/lib/nonstandard/index.mjs +207 -40
  10. package/lib/rtp/src/index.d.ts +1 -0
  11. package/lib/rtp/src/index.js +1 -0
  12. package/lib/rtp/src/index.js.map +1 -1
  13. package/lib/rtp/src/srtp/cipher/ctr.d.ts +3 -3
  14. package/lib/rtp/src/srtp/cipher/ctr.js +25 -14
  15. package/lib/rtp/src/srtp/cipher/ctr.js.map +1 -1
  16. package/lib/rtp/src/srtp/cipher/gcm.d.ts +3 -3
  17. package/lib/rtp/src/srtp/cipher/gcm.js +57 -20
  18. package/lib/rtp/src/srtp/cipher/gcm.js.map +1 -1
  19. package/lib/rtp/src/srtp/cipher/index.d.ts +1 -1
  20. package/lib/rtp/src/srtp/cipher/index.js +1 -1
  21. package/lib/rtp/src/srtp/cipher/index.js.map +1 -1
  22. package/lib/rtp/src/srtp/context/srtp.d.ts +2 -1
  23. package/lib/rtp/src/srtp/context/srtp.js +22 -5
  24. package/lib/rtp/src/srtp/context/srtp.js.map +1 -1
  25. package/lib/rtp/src/srtp/error.d.ts +3 -0
  26. package/lib/rtp/src/srtp/error.js +11 -0
  27. package/lib/rtp/src/srtp/error.js.map +1 -0
  28. package/lib/rtp/src/srtp/packet.d.ts +5 -0
  29. package/lib/rtp/src/srtp/packet.js +48 -0
  30. package/lib/rtp/src/srtp/packet.js.map +1 -0
  31. package/lib/webrtc/src/dataChannel.d.ts +1 -0
  32. package/lib/webrtc/src/dataChannel.js +5 -2
  33. package/lib/webrtc/src/dataChannel.js.map +1 -1
  34. package/lib/webrtc/src/peerConnection.d.ts +4 -1
  35. package/lib/webrtc/src/peerConnection.js +26 -5
  36. package/lib/webrtc/src/peerConnection.js.map +1 -1
  37. package/lib/webrtc/src/sctpManager.d.ts +1 -1
  38. package/lib/webrtc/src/sctpManager.js +3 -2
  39. package/lib/webrtc/src/sctpManager.js.map +1 -1
  40. package/lib/webrtc/src/sdpManager.d.ts +1 -1
  41. package/lib/webrtc/src/sdpManager.js +3 -4
  42. package/lib/webrtc/src/sdpManager.js.map +1 -1
  43. package/lib/webrtc/src/secureTransportManager.js +1 -1
  44. package/lib/webrtc/src/secureTransportManager.js.map +1 -1
  45. package/lib/webrtc/src/transceiverManager.js +3 -2
  46. package/lib/webrtc/src/transceiverManager.js.map +1 -1
  47. package/lib/webrtc/src/transport/dtls.d.ts +1 -0
  48. package/lib/webrtc/src/transport/dtls.js +117 -12
  49. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  50. package/lib/webrtc/src/transport/sctp.d.ts +9 -3
  51. package/lib/webrtc/src/transport/sctp.js +35 -7
  52. package/lib/webrtc/src/transport/sctp.js.map +1 -1
  53. package/lib/webrtc/src/utils.d.ts +2 -0
  54. package/lib/webrtc/src/utils.js +20 -0
  55. package/lib/webrtc/src/utils.js.map +1 -1
  56. package/package.json +1 -1
@@ -4477,7 +4477,12 @@ import { createHmac as createHmac2 } from "crypto";
4477
4477
  import AES from "aes-js";
4478
4478
 
4479
4479
  // ../rtp/src/srtp/cipher/ctr.ts
4480
- import { createCipheriv as createCipheriv2, createDecipheriv, createHmac } from "crypto";
4480
+ import {
4481
+ createCipheriv as createCipheriv2,
4482
+ createDecipheriv,
4483
+ createHmac,
4484
+ timingSafeEqual
4485
+ } from "crypto";
4481
4486
 
4482
4487
  // ../rtp/src/srtp/cipher/index.ts
4483
4488
  var CipherAesBase = class {
@@ -4490,7 +4495,7 @@ var CipherAesBase = class {
4490
4495
  encryptRtp(header, payload, rolloverCounter) {
4491
4496
  return Buffer.from([]);
4492
4497
  }
4493
- decryptRtp(cipherText, rolloverCounter) {
4498
+ decryptRtp(cipherText, rolloverCounter, header) {
4494
4499
  return [];
4495
4500
  }
4496
4501
  encryptRTCP(rawRtcp, srtcpIndex) {
@@ -4501,6 +4506,74 @@ var CipherAesBase = class {
4501
4506
  }
4502
4507
  };
4503
4508
 
4509
+ // ../rtp/src/srtp/error.ts
4510
+ var SrtpAuthenticationError = class extends Error {
4511
+ constructor(message) {
4512
+ super(message);
4513
+ this.name = "SrtpAuthenticationError";
4514
+ }
4515
+ };
4516
+
4517
+ // ../rtp/src/srtp/packet.ts
4518
+ var minRtpHeaderSize = 12;
4519
+ var minRtcpPacketSize = 8;
4520
+ function parseSrtpRtpHeader(packet, authTagLength, message = "Failed to authenticate SRTP packet") {
4521
+ const authTagOffset = packet.length - authTagLength;
4522
+ assertAuthenticatedPacketLength(
4523
+ packet.length >= minRtpHeaderSize + authTagLength,
4524
+ message
4525
+ );
4526
+ const header = wrapAuthenticationError(
4527
+ () => RtpHeader.deSerialize(packet.subarray(0, authTagOffset)),
4528
+ message
4529
+ );
4530
+ header.paddingSize = 0;
4531
+ assertAuthenticatedPacketLength(
4532
+ header.payloadOffset >= minRtpHeaderSize && header.payloadOffset <= authTagOffset,
4533
+ message
4534
+ );
4535
+ return header;
4536
+ }
4537
+ function parseSrtcpHeader(packet, authTagLength, srtcpIndexSize3, message = "Failed to authenticate SRTCP packet") {
4538
+ assertAuthenticatedPacketLength(
4539
+ packet.length >= minRtcpPacketSize + authTagLength + srtcpIndexSize3,
4540
+ message
4541
+ );
4542
+ return wrapAuthenticationError(
4543
+ () => RtcpHeader.deSerialize(packet.subarray(0, RTCP_HEADER_SIZE)),
4544
+ message
4545
+ );
4546
+ }
4547
+ function assertAuthenticatedPacketLength(condition, message) {
4548
+ if (!condition) {
4549
+ throw new SrtpAuthenticationError(message);
4550
+ }
4551
+ }
4552
+ function wrapAuthenticationError(parse, message) {
4553
+ try {
4554
+ return parse();
4555
+ } catch {
4556
+ throw new SrtpAuthenticationError(message);
4557
+ }
4558
+ }
4559
+ function finalizeSrtpRtpHeader(header, packet, message = "Failed to authenticate SRTP packet") {
4560
+ if (!header.padding) {
4561
+ header.paddingSize = 0;
4562
+ return header;
4563
+ }
4564
+ assertAuthenticatedPacketLength(
4565
+ packet.length > header.payloadOffset,
4566
+ message
4567
+ );
4568
+ const paddingSize = packet[packet.length - 1];
4569
+ assertAuthenticatedPacketLength(
4570
+ paddingSize > 0 && paddingSize <= packet.length - header.payloadOffset,
4571
+ message
4572
+ );
4573
+ header.paddingSize = paddingSize;
4574
+ return header;
4575
+ }
4576
+
4504
4577
  // ../rtp/src/srtp/cipher/ctr.ts
4505
4578
  var CipherAesCtr = class extends CipherAesBase {
4506
4579
  constructor(srtpSessionKey, srtpSessionSalt, srtcpSessionKey, srtcpSessionSalt, srtpSessionAuthTag, srtcpSessionAuthTag) {
@@ -4526,10 +4599,20 @@ var CipherAesCtr = class extends CipherAesBase {
4526
4599
  );
4527
4600
  return Buffer.concat([headerBuffer, enc, authTag]);
4528
4601
  }
4529
- decryptRtp(cipherText, rolloverCounter) {
4530
- const header = RtpHeader.deSerialize(cipherText);
4531
- const size = cipherText.length - this.authTagLength;
4532
- cipherText = cipherText.subarray(0, cipherText.length - this.authTagLength);
4602
+ decryptRtp(cipherText, rolloverCounter, header = parseSrtpRtpHeader(cipherText, this.authTagLength)) {
4603
+ const authTagOffset = cipherText.length - this.authTagLength;
4604
+ const encryptedPacket = cipherText.subarray(0, authTagOffset);
4605
+ const actualAuthTag = cipherText.subarray(authTagOffset);
4606
+ const expectedAuthTag = this.generateSrtpAuthTag(
4607
+ rolloverCounter,
4608
+ encryptedPacket.subarray(0, header.payloadOffset),
4609
+ encryptedPacket.subarray(header.payloadOffset)
4610
+ );
4611
+ assertAuthTag(
4612
+ actualAuthTag,
4613
+ expectedAuthTag,
4614
+ "Failed to authenticate SRTP packet"
4615
+ );
4533
4616
  const counter = this.generateCounter(
4534
4617
  header.sequenceNumber,
4535
4618
  rolloverCounter,
@@ -4541,14 +4624,16 @@ var CipherAesCtr = class extends CipherAesBase {
4541
4624
  this.srtpSessionKey,
4542
4625
  counter
4543
4626
  );
4544
- const payload = cipherText.subarray(header.payloadOffset);
4627
+ const payload = encryptedPacket.subarray(header.payloadOffset);
4545
4628
  const buf = cipher.update(payload);
4546
4629
  const dst = Buffer.concat([
4547
- cipherText.subarray(0, header.payloadOffset),
4548
- buf,
4549
- Buffer.alloc(size - header.payloadOffset - buf.length)
4630
+ encryptedPacket.subarray(0, header.payloadOffset),
4631
+ buf
4550
4632
  ]);
4551
- return [dst, header];
4633
+ return [
4634
+ dst,
4635
+ finalizeSrtpRtpHeader(header, dst, "Failed to authenticate SRTP packet")
4636
+ ];
4552
4637
  }
4553
4638
  encryptRTCP(rtcpPacket, srtcpIndex) {
4554
4639
  let out = Buffer.from(rtcpPacket);
@@ -4570,15 +4655,29 @@ var CipherAesCtr = class extends CipherAesBase {
4570
4655
  return out;
4571
4656
  }
4572
4657
  decryptRTCP(encrypted) {
4573
- const header = RtcpHeader.deSerialize(encrypted);
4658
+ const header = parseSrtcpHeader(
4659
+ encrypted,
4660
+ this.authTagLength,
4661
+ srtcpIndexSize
4662
+ );
4574
4663
  const tailOffset = encrypted.length - (this.authTagLength + srtcpIndexSize);
4664
+ const authenticatedPortion = encrypted.subarray(
4665
+ 0,
4666
+ encrypted.length - this.authTagLength
4667
+ );
4668
+ const actualTag = encrypted.subarray(encrypted.length - this.authTagLength);
4669
+ const expectedTag = this.generateSrtcpAuthTag(authenticatedPortion);
4670
+ assertAuthTag(
4671
+ actualTag,
4672
+ expectedTag,
4673
+ "Failed to authenticate SRTCP packet"
4674
+ );
4575
4675
  const out = Buffer.from(encrypted).slice(0, tailOffset);
4576
- const isEncrypted = encrypted[tailOffset] >> 7;
4676
+ const isEncrypted = encrypted[tailOffset] >>> 7;
4577
4677
  if (isEncrypted === 0) return [out, header];
4578
4678
  let srtcpIndex = encrypted.readUInt32BE(tailOffset);
4579
4679
  srtcpIndex &= ~(1 << 31);
4580
4680
  const ssrc = encrypted.readUInt32BE(4);
4581
- const actualTag = encrypted.subarray(encrypted.length - 10);
4582
4681
  const counter = this.generateCounter(
4583
4682
  srtcpIndex & 65535,
4584
4683
  srtcpIndex >> 16,
@@ -4619,6 +4718,11 @@ var CipherAesCtr = class extends CipherAesBase {
4619
4718
  }
4620
4719
  };
4621
4720
  var srtcpIndexSize = 4;
4721
+ function assertAuthTag(actual, expected, message) {
4722
+ if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) {
4723
+ throw new SrtpAuthenticationError(message);
4724
+ }
4725
+ }
4622
4726
 
4623
4727
  // ../rtp/src/srtp/cipher/gcm.ts
4624
4728
  import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv2 } from "crypto";
@@ -4641,20 +4745,25 @@ var CipherAesGcm = class extends CipherAesBase {
4641
4745
  const dst = Buffer.concat([hdr, enc, authTag]);
4642
4746
  return dst;
4643
4747
  }
4644
- decryptRtp(cipherText, rolloverCounter) {
4645
- const header = RtpHeader.deSerialize(cipherText);
4748
+ decryptRtp(cipherText, rolloverCounter, header = parseSrtpRtpHeader(cipherText, this.aeadAuthTagLen)) {
4749
+ const headerBuffer = cipherText.subarray(0, header.payloadOffset);
4750
+ const authTagOffset = cipherText.length - this.aeadAuthTagLen;
4751
+ const authTag = cipherText.subarray(authTagOffset);
4646
4752
  let dst = Buffer.from([]);
4647
4753
  dst = growBufferSize(dst, cipherText.length - this.aeadAuthTagLen);
4648
- cipherText.slice(0, header.payloadOffset).copy(dst);
4754
+ headerBuffer.copy(dst);
4649
4755
  const iv = this.rtpInitializationVector(header, rolloverCounter);
4650
- const enc = cipherText.slice(
4651
- header.payloadOffset,
4652
- cipherText.length - this.aeadAuthTagLen
4653
- );
4654
- const cipher = createDecipheriv2("aes-128-gcm", this.srtpSessionKey, iv);
4655
- const dec = cipher.update(enc);
4756
+ const enc = cipherText.slice(header.payloadOffset, authTagOffset);
4757
+ const decipher = createDecipheriv2("aes-128-gcm", this.srtpSessionKey, iv);
4758
+ decipher.setAAD(headerBuffer);
4759
+ decipher.setAuthTag(authTag);
4760
+ const dec = decipher.update(enc);
4761
+ finalizeAuthenticatedDecryption(decipher, "SRTP");
4656
4762
  dec.copy(dst, header.payloadOffset);
4657
- return [dst, header];
4763
+ return [
4764
+ dst,
4765
+ finalizeSrtpRtpHeader(header, dst, "Failed to authenticate SRTP packet")
4766
+ ];
4658
4767
  }
4659
4768
  encryptRTCP(rtcpPacket, srtcpIndex) {
4660
4769
  const ssrc = rtcpPacket.readUInt32BE(4);
@@ -4675,19 +4784,38 @@ var CipherAesGcm = class extends CipherAesBase {
4675
4784
  return dst;
4676
4785
  }
4677
4786
  decryptRTCP(encrypted) {
4678
- const header = RtcpHeader.deSerialize(encrypted);
4679
- const aadPos = encrypted.length - srtcpIndexSize2;
4680
- const dst = Buffer.alloc(aadPos - this.aeadAuthTagLen);
4681
- encrypted.slice(0, 8).copy(dst);
4787
+ const header = parseSrtcpHeader(
4788
+ encrypted,
4789
+ this.aeadAuthTagLen,
4790
+ srtcpIndexSize2
4791
+ );
4792
+ const srtcpIndexOffset = encrypted.length - srtcpIndexSize2;
4793
+ const authTagOffset = srtcpIndexOffset - this.aeadAuthTagLen;
4682
4794
  const ssrc = encrypted.readUInt32BE(4);
4683
- let srtcpIndex = encrypted.readUInt32BE(encrypted.length - 4);
4684
- srtcpIndex &= ~(rtcpEncryptionFlag << 24);
4795
+ const encodedSrtcpIndex = encrypted.readUInt32BE(srtcpIndexOffset);
4796
+ const isEncrypted = encodedSrtcpIndex >>> 31 === 1;
4797
+ const srtcpIndex = encodedSrtcpIndex & ~(rtcpEncryptionFlag << 24);
4685
4798
  const iv = this.rtcpInitializationVector(ssrc, srtcpIndex);
4686
- const aad = this.rtcpAdditionalAuthenticatedData(encrypted, srtcpIndex);
4687
- const cipher = createDecipheriv2("aes-128-gcm", this.srtcpSessionKey, iv);
4688
- cipher.setAAD(aad);
4689
- const dec = cipher.update(encrypted.slice(8, aadPos));
4690
- dec.copy(dst, 8);
4799
+ const aad = isEncrypted ? Buffer.concat([
4800
+ encrypted.subarray(0, 8),
4801
+ encrypted.subarray(srtcpIndexOffset)
4802
+ ]) : Buffer.concat([
4803
+ encrypted.subarray(0, authTagOffset),
4804
+ encrypted.subarray(srtcpIndexOffset)
4805
+ ]);
4806
+ const cipherText = isEncrypted ? encrypted.slice(8, authTagOffset) : Buffer.alloc(0);
4807
+ const dst = isEncrypted ? Buffer.alloc(authTagOffset) : Buffer.from(encrypted.subarray(0, authTagOffset));
4808
+ if (isEncrypted) {
4809
+ encrypted.slice(0, 8).copy(dst);
4810
+ }
4811
+ const decipher = createDecipheriv2("aes-128-gcm", this.srtcpSessionKey, iv);
4812
+ decipher.setAAD(aad);
4813
+ decipher.setAuthTag(encrypted.subarray(authTagOffset, srtcpIndexOffset));
4814
+ const dec = decipher.update(cipherText);
4815
+ finalizeAuthenticatedDecryption(decipher, "SRTCP");
4816
+ if (isEncrypted) {
4817
+ dec.copy(dst, 8);
4818
+ }
4691
4819
  return [dst, header];
4692
4820
  }
4693
4821
  // https://tools.ietf.org/html/rfc7714#section-8.1
@@ -4723,6 +4851,15 @@ var CipherAesGcm = class extends CipherAesBase {
4723
4851
  };
4724
4852
  var srtcpIndexSize2 = 4;
4725
4853
  var rtcpEncryptionFlag = 128;
4854
+ function finalizeAuthenticatedDecryption(decipher, packetType) {
4855
+ try {
4856
+ decipher.final();
4857
+ } catch {
4858
+ throw new SrtpAuthenticationError(
4859
+ `Failed to authenticate ${packetType} packet`
4860
+ );
4861
+ }
4862
+ }
4726
4863
 
4727
4864
  // ../rtp/src/srtp/context/context.ts
4728
4865
  var Context = class {
@@ -4980,12 +5117,29 @@ var SrtpContext = class extends Context {
4980
5117
  return enc;
4981
5118
  }
4982
5119
  decryptRtp(cipherText) {
4983
- const header = RtpHeader.deSerialize(cipherText);
4984
- const s = this.getSrtpSsrcState(header.ssrc);
4985
- this.updateRolloverCount(header.sequenceNumber, s);
4986
- const dec = this.cipher.decryptRtp(cipherText, s.rolloverCounter);
5120
+ const header = parseSrtpRtpHeader(cipherText, this.rtpAuthTagLength);
5121
+ const existingState = this.srtpSSRCStates[header.ssrc];
5122
+ const nextState = existingState ? { ...existingState } : {
5123
+ ssrc: header.ssrc,
5124
+ rolloverCounter: 0,
5125
+ lastSequenceNumber: 0
5126
+ };
5127
+ this.updateRolloverCount(header.sequenceNumber, nextState);
5128
+ const dec = this.cipher.decryptRtp(
5129
+ cipherText,
5130
+ nextState.rolloverCounter,
5131
+ header
5132
+ );
5133
+ if (existingState) {
5134
+ Object.assign(existingState, nextState);
5135
+ } else {
5136
+ this.srtpSSRCStates[header.ssrc] = nextState;
5137
+ }
4987
5138
  return dec;
4988
5139
  }
5140
+ get rtpAuthTagLength() {
5141
+ return this.profile === ProtectionProfileAeadAes128Gcm ? 16 : 10;
5142
+ }
4989
5143
  };
4990
5144
 
4991
5145
  // ../rtp/src/srtp/srtp.ts
@@ -8508,6 +8662,16 @@ handlers2[16 /* client_key_exchange_16 */] = ({ cipher, dtls }) => (message) =>
8508
8662
  );
8509
8663
  log18(dtls.sessionId, "setup cipher", cipher.cipher.summary);
8510
8664
  };
8665
+ handlers2[11 /* certificate_11 */] = ({ cipher, dtls }) => (message) => {
8666
+ log18(dtls.sessionId, "handshake certificate", message);
8667
+ cipher.remoteCertificate = message.certificateList[0];
8668
+ };
8669
+ handlers2[15 /* certificate_verify_15 */] = ({ cipher, dtls }) => (message) => {
8670
+ if (!cipher.remoteCertificate) {
8671
+ throw new Error("client certificate missing before certificate verify");
8672
+ }
8673
+ log18(dtls.sessionId, "certificate_verify", message.algorithm);
8674
+ };
8511
8675
  handlers2[20 /* finished_20 */] = ({ dtls }) => (message) => {
8512
8676
  log18(dtls.sessionId, "finished", message);
8513
8677
  };
@@ -9301,6 +9465,7 @@ var SCTP_TSN_MODULO = 2 ** 32;
9301
9465
 
9302
9466
  // src/transport/sctp.ts
9303
9467
  var log32 = debug("werift:packages/webrtc/src/transport/sctp.ts");
9468
+ var DEFAULT_MAX_MESSAGE_SIZE = 65536;
9304
9469
 
9305
9470
  // src/media/rtpReceiver.ts
9306
9471
  var log33 = debug("werift:packages/webrtc/src/media/rtpReceiver.ts");
@@ -9352,7 +9517,8 @@ function generateDefaultPeerConfig() {
9352
9517
  bundlePolicy: "max-compat",
9353
9518
  debug: {},
9354
9519
  midSuffix: false,
9355
- forceTurnTCP: false
9520
+ forceTurnTCP: false,
9521
+ maxMessageSize: DEFAULT_MAX_MESSAGE_SIZE
9356
9522
  };
9357
9523
  }
9358
9524
  var defaultPeerConfig = generateDefaultPeerConfig();
@@ -9818,6 +9984,7 @@ export {
9818
9984
  SourceDescriptionChunk,
9819
9985
  SourceDescriptionItem,
9820
9986
  SrtcpSession,
9987
+ SrtpAuthenticationError,
9821
9988
  SrtpSession,
9822
9989
  StatusVectorChunk,
9823
9990
  TcpTransport,
@@ -22,4 +22,5 @@ export * from "./rtp/rtp";
22
22
  export * from "./rtp/rtx";
23
23
  export * from "./srtp/srtcp";
24
24
  export * from "./srtp/srtp";
25
+ export * from "./srtp/error";
25
26
  export * from "./util";
@@ -38,5 +38,6 @@ __exportStar(require("./rtp/rtp"), exports);
38
38
  __exportStar(require("./rtp/rtx"), exports);
39
39
  __exportStar(require("./srtp/srtcp"), exports);
40
40
  __exportStar(require("./srtp/srtp"), exports);
41
+ __exportStar(require("./srtp/error"), exports);
41
42
  __exportStar(require("./util"), exports);
42
43
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../rtp/src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kBAAgB;AAChB,+CAA6B;AAC7B,mDAAiC;AACjC,0CAAwB;AACxB,2CAAyB;AACzB,gDAA8B;AAC9B,8CAA4B;AAC5B,oEAAkD;AAClD,mDAAiC;AACjC,4CAA0B;AAC1B,8CAA4B;AAC5B,+CAA6B;AAC7B,oDAAkC;AAClC,oDAAkC;AAClC,8CAA4B;AAC5B,4CAA0B;AAC1B,wDAAsC;AACtC,oDAAkC;AAClC,oDAAkC;AAClC,mDAAiC;AACjC,4CAA0B;AAC1B,4CAA0B;AAC1B,+CAA6B;AAC7B,8CAA4B;AAC5B,yCAAuB","sourcesContent":["import \"buffer\";\nexport * from \"./srtp/const\";\nexport * from \"../../common/src\";\nexport * from \"./codec\";\nexport * from \"./helper\";\nexport * from \"./rtcp/header\";\nexport * from \"./rtcp/psfb\";\nexport * from \"./rtcp/psfb/pictureLossIndication\";\nexport * from \"./rtcp/psfb/remb\";\nexport * from \"./rtcp/rr\";\nexport * from \"./rtcp/rtcp\";\nexport * from \"./rtcp/rtpfb\";\nexport * from \"./rtcp/rtpfb/nack\";\nexport * from \"./rtcp/rtpfb/twcc\";\nexport * from \"./rtcp/sdes\";\nexport * from \"./rtcp/sr\";\nexport * from \"./rtp/headerExtension\";\nexport * from \"./rtp/red/encoder\";\nexport * from \"./rtp/red/handler\";\nexport * from \"./rtp/red/packet\";\nexport * from \"./rtp/rtp\";\nexport * from \"./rtp/rtx\";\nexport * from \"./srtp/srtcp\";\nexport * from \"./srtp/srtp\";\nexport * from \"./util\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../rtp/src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kBAAgB;AAChB,+CAA6B;AAC7B,mDAAiC;AACjC,0CAAwB;AACxB,2CAAyB;AACzB,gDAA8B;AAC9B,8CAA4B;AAC5B,oEAAkD;AAClD,mDAAiC;AACjC,4CAA0B;AAC1B,8CAA4B;AAC5B,+CAA6B;AAC7B,oDAAkC;AAClC,oDAAkC;AAClC,8CAA4B;AAC5B,4CAA0B;AAC1B,wDAAsC;AACtC,oDAAkC;AAClC,oDAAkC;AAClC,mDAAiC;AACjC,4CAA0B;AAC1B,4CAA0B;AAC1B,+CAA6B;AAC7B,8CAA4B;AAC5B,+CAA6B;AAC7B,yCAAuB","sourcesContent":["import \"buffer\";\nexport * from \"./srtp/const\";\nexport * from \"../../common/src\";\nexport * from \"./codec\";\nexport * from \"./helper\";\nexport * from \"./rtcp/header\";\nexport * from \"./rtcp/psfb\";\nexport * from \"./rtcp/psfb/pictureLossIndication\";\nexport * from \"./rtcp/psfb/remb\";\nexport * from \"./rtcp/rr\";\nexport * from \"./rtcp/rtcp\";\nexport * from \"./rtcp/rtpfb\";\nexport * from \"./rtcp/rtpfb/nack\";\nexport * from \"./rtcp/rtpfb/twcc\";\nexport * from \"./rtcp/sdes\";\nexport * from \"./rtcp/sr\";\nexport * from \"./rtp/headerExtension\";\nexport * from \"./rtp/red/encoder\";\nexport * from \"./rtp/red/handler\";\nexport * from \"./rtp/red/packet\";\nexport * from \"./rtp/rtp\";\nexport * from \"./rtp/rtx\";\nexport * from \"./srtp/srtcp\";\nexport * from \"./srtp/srtp\";\nexport * from \"./srtp/error\";\nexport * from \"./util\";\n"]}
@@ -1,13 +1,13 @@
1
1
  import { CipherAesBase } from ".";
2
- import { RtcpHeader } from "../../rtcp/header";
3
- import { RtpHeader } from "../../rtp/rtp";
2
+ import type { RtcpHeader } from "../../rtcp/header";
3
+ import type { RtpHeader } from "../../rtp/rtp";
4
4
  export declare class CipherAesCtr extends CipherAesBase {
5
5
  private srtpSessionAuthTag;
6
6
  private srtcpSessionAuthTag;
7
7
  readonly authTagLength = 10;
8
8
  constructor(srtpSessionKey: Buffer, srtpSessionSalt: Buffer, srtcpSessionKey: Buffer, srtcpSessionSalt: Buffer, srtpSessionAuthTag: Buffer, srtcpSessionAuthTag: Buffer);
9
9
  encryptRtp(header: RtpHeader, payload: Buffer, rolloverCounter: number): Buffer<ArrayBuffer>;
10
- decryptRtp(cipherText: Buffer, rolloverCounter: number): [Buffer, RtpHeader];
10
+ decryptRtp(cipherText: Buffer, rolloverCounter: number, header?: RtpHeader): [Buffer, RtpHeader];
11
11
  encryptRTCP(rtcpPacket: Buffer, srtcpIndex: number): Buffer;
12
12
  decryptRTCP(encrypted: Buffer): [Buffer, RtcpHeader];
13
13
  generateSrtcpAuthTag(buf: Buffer): Buffer<ArrayBuffer>;
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CipherAesCtr = void 0;
4
4
  const crypto_1 = require("crypto");
5
5
  const _1 = require(".");
6
- const header_1 = require("../../rtcp/header");
7
- const rtp_1 = require("../../rtp/rtp");
6
+ const error_1 = require("../error");
7
+ const packet_1 = require("../packet");
8
8
  class CipherAesCtr extends _1.CipherAesBase {
9
9
  constructor(srtpSessionKey, srtpSessionSalt, srtcpSessionKey, srtcpSessionSalt, srtpSessionAuthTag, srtcpSessionAuthTag) {
10
10
  super(srtpSessionKey, srtpSessionSalt, srtcpSessionKey, srtcpSessionSalt);
@@ -35,20 +35,24 @@ class CipherAesCtr extends _1.CipherAesBase {
35
35
  const authTag = this.generateSrtpAuthTag(rolloverCounter, headerBuffer, enc);
36
36
  return Buffer.concat([headerBuffer, enc, authTag]);
37
37
  }
38
- decryptRtp(cipherText, rolloverCounter) {
39
- const header = rtp_1.RtpHeader.deSerialize(cipherText);
40
- const size = cipherText.length - this.authTagLength;
41
- cipherText = cipherText.subarray(0, cipherText.length - this.authTagLength);
38
+ decryptRtp(cipherText, rolloverCounter, header = (0, packet_1.parseSrtpRtpHeader)(cipherText, this.authTagLength)) {
39
+ const authTagOffset = cipherText.length - this.authTagLength;
40
+ const encryptedPacket = cipherText.subarray(0, authTagOffset);
41
+ const actualAuthTag = cipherText.subarray(authTagOffset);
42
+ const expectedAuthTag = this.generateSrtpAuthTag(rolloverCounter, encryptedPacket.subarray(0, header.payloadOffset), encryptedPacket.subarray(header.payloadOffset));
43
+ assertAuthTag(actualAuthTag, expectedAuthTag, "Failed to authenticate SRTP packet");
42
44
  const counter = this.generateCounter(header.sequenceNumber, rolloverCounter, header.ssrc, this.srtpSessionSalt);
43
45
  const cipher = (0, crypto_1.createDecipheriv)("aes-128-ctr", this.srtpSessionKey, counter);
44
- const payload = cipherText.subarray(header.payloadOffset);
46
+ const payload = encryptedPacket.subarray(header.payloadOffset);
45
47
  const buf = cipher.update(payload);
46
48
  const dst = Buffer.concat([
47
- cipherText.subarray(0, header.payloadOffset),
49
+ encryptedPacket.subarray(0, header.payloadOffset),
48
50
  buf,
49
- Buffer.alloc(size - header.payloadOffset - buf.length),
50
51
  ]);
51
- return [dst, header];
52
+ return [
53
+ dst,
54
+ (0, packet_1.finalizeSrtpRtpHeader)(header, dst, "Failed to authenticate SRTP packet"),
55
+ ];
52
56
  }
53
57
  encryptRTCP(rtcpPacket, srtcpIndex) {
54
58
  let out = Buffer.from(rtcpPacket);
@@ -66,17 +70,19 @@ class CipherAesCtr extends _1.CipherAesBase {
66
70
  return out;
67
71
  }
68
72
  decryptRTCP(encrypted) {
69
- const header = header_1.RtcpHeader.deSerialize(encrypted);
73
+ const header = (0, packet_1.parseSrtcpHeader)(encrypted, this.authTagLength, srtcpIndexSize);
70
74
  const tailOffset = encrypted.length - (this.authTagLength + srtcpIndexSize);
75
+ const authenticatedPortion = encrypted.subarray(0, encrypted.length - this.authTagLength);
76
+ const actualTag = encrypted.subarray(encrypted.length - this.authTagLength);
77
+ const expectedTag = this.generateSrtcpAuthTag(authenticatedPortion);
78
+ assertAuthTag(actualTag, expectedTag, "Failed to authenticate SRTCP packet");
71
79
  const out = Buffer.from(encrypted).slice(0, tailOffset);
72
- const isEncrypted = encrypted[tailOffset] >> 7;
80
+ const isEncrypted = encrypted[tailOffset] >>> 7;
73
81
  if (isEncrypted === 0)
74
82
  return [out, header];
75
83
  let srtcpIndex = encrypted.readUInt32BE(tailOffset);
76
84
  srtcpIndex &= ~(1 << 31);
77
85
  const ssrc = encrypted.readUInt32BE(4);
78
- // todo impl compare
79
- const actualTag = encrypted.subarray(encrypted.length - 10);
80
86
  const counter = this.generateCounter(srtcpIndex & 0xffff, srtcpIndex >> 16, ssrc, this.srtcpSessionSalt);
81
87
  const cipher = (0, crypto_1.createDecipheriv)("aes-128-ctr", this.srtcpSessionKey, counter);
82
88
  const buf = cipher.update(out.subarray(8));
@@ -109,4 +115,9 @@ class CipherAesCtr extends _1.CipherAesBase {
109
115
  }
110
116
  exports.CipherAesCtr = CipherAesCtr;
111
117
  const srtcpIndexSize = 4;
118
+ function assertAuthTag(actual, expected, message) {
119
+ if (actual.length !== expected.length || !(0, crypto_1.timingSafeEqual)(actual, expected)) {
120
+ throw new error_1.SrtpAuthenticationError(message);
121
+ }
122
+ }
112
123
  //# sourceMappingURL=ctr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ctr.js","sourceRoot":"","sources":["../../../../../../rtp/src/srtp/cipher/ctr.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCipheriv, createDecipheriv, createHmac } from \"crypto\";\n\nimport { CipherAesBase } from \".\";\nimport { RtcpHeader } from \"../../rtcp/header\";\nimport { RtpHeader } from \"../../rtp/rtp\";\n\nexport class CipherAesCtr extends CipherAesBase {\n readonly authTagLength = 10;\n\n constructor(\n srtpSessionKey: Buffer,\n srtpSessionSalt: Buffer,\n srtcpSessionKey: Buffer,\n srtcpSessionSalt: Buffer,\n private srtpSessionAuthTag: Buffer,\n private srtcpSessionAuthTag: Buffer,\n ) {\n super(srtpSessionKey, srtpSessionSalt, srtcpSessionKey, srtcpSessionSalt);\n }\n\n encryptRtp(header: RtpHeader, payload: Buffer, rolloverCounter: number) {\n const headerBuffer = header.serialize(header.serializeSize);\n\n const counter = this.generateCounter(\n header.sequenceNumber,\n rolloverCounter,\n header.ssrc,\n this.srtpSessionSalt,\n );\n\n const cipher = createCipheriv(\"aes-128-ctr\", this.srtpSessionKey, counter);\n const enc = cipher.update(payload);\n\n const authTag = this.generateSrtpAuthTag(\n rolloverCounter,\n headerBuffer,\n enc,\n );\n return Buffer.concat([headerBuffer, enc, authTag]);\n }\n\n decryptRtp(cipherText: Buffer, rolloverCounter: number): [Buffer, RtpHeader] {\n const header = RtpHeader.deSerialize(cipherText);\n\n const size = cipherText.length - this.authTagLength;\n\n cipherText = cipherText.subarray(0, cipherText.length - this.authTagLength);\n\n const counter = this.generateCounter(\n header.sequenceNumber,\n rolloverCounter,\n header.ssrc,\n this.srtpSessionSalt,\n );\n const cipher = createDecipheriv(\n \"aes-128-ctr\",\n this.srtpSessionKey,\n counter,\n );\n const payload = cipherText.subarray(header.payloadOffset);\n const buf = cipher.update(payload);\n\n const dst = Buffer.concat([\n cipherText.subarray(0, header.payloadOffset),\n buf,\n Buffer.alloc(size - header.payloadOffset - buf.length),\n ]);\n\n return [dst, header];\n }\n\n encryptRTCP(rtcpPacket: Buffer, srtcpIndex: number): Buffer {\n let out = Buffer.from(rtcpPacket);\n const ssrc = out.readUInt32BE(4);\n\n const counter = this.generateCounter(\n srtcpIndex & 0xffff,\n srtcpIndex >> 16,\n ssrc,\n this.srtcpSessionSalt,\n );\n const cipher = createCipheriv(\"aes-128-ctr\", this.srtcpSessionKey, counter);\n // Encrypt everything after header\n const buf = cipher.update(out.slice(8));\n buf.copy(out, 8);\n out = Buffer.concat([out, Buffer.alloc(4)]);\n out.writeUInt32BE(srtcpIndex, out.length - 4);\n out[out.length - 4] |= 0x80;\n const authTag = this.generateSrtcpAuthTag(out);\n out = Buffer.concat([out, authTag]);\n\n return out;\n }\n\n decryptRTCP(encrypted: Buffer): [Buffer, RtcpHeader] {\n const header = RtcpHeader.deSerialize(encrypted);\n\n const tailOffset = encrypted.length - (this.authTagLength + srtcpIndexSize);\n const out = Buffer.from(encrypted).slice(0, tailOffset);\n\n const isEncrypted = encrypted[tailOffset] >> 7;\n if (isEncrypted === 0) return [out, header];\n\n let srtcpIndex = encrypted.readUInt32BE(tailOffset);\n srtcpIndex &= ~(1 << 31);\n\n const ssrc = encrypted.readUInt32BE(4);\n\n // todo impl compare\n const actualTag = encrypted.subarray(encrypted.length - 10);\n\n const counter = this.generateCounter(\n srtcpIndex & 0xffff,\n srtcpIndex >> 16,\n ssrc,\n this.srtcpSessionSalt,\n );\n const cipher = createDecipheriv(\n \"aes-128-ctr\",\n this.srtcpSessionKey,\n counter,\n );\n const buf = cipher.update(out.subarray(8));\n buf.copy(out, 8);\n return [out, header];\n }\n\n generateSrtcpAuthTag(buf: Buffer) {\n const srtcpSessionAuth = createHmac(\"sha1\", this.srtcpSessionAuthTag);\n return srtcpSessionAuth.update(buf).digest().slice(0, 10);\n }\n\n generateCounter(\n sequenceNumber: number,\n rolloverCounter: number,\n ssrc: number,\n sessionSalt: Buffer,\n ) {\n const counter = Buffer.alloc(16);\n counter.writeUInt32BE(ssrc, 4);\n counter.writeUInt32BE(rolloverCounter, 8);\n counter.writeUInt32BE(Number(BigInt(sequenceNumber) << 16n), 12);\n\n for (let i = 0; i < sessionSalt.length; i++) {\n counter[i] ^= sessionSalt[i];\n }\n return counter;\n }\n\n generateSrtpAuthTag(roc: number, ...buffers: Buffer[]) {\n const srtpSessionAuth = createHmac(\"sha1\", this.srtpSessionAuthTag);\n const rocRaw = Buffer.alloc(4);\n rocRaw.writeUInt32BE(roc);\n\n for (const buf of buffers) {\n srtpSessionAuth.update(buf);\n }\n return srtpSessionAuth.update(rocRaw).digest().subarray(0, 10);\n }\n}\n\nconst srtcpIndexSize = 4;\n"]}
1
+ {"version":3,"file":"ctr.js","sourceRoot":"","sources":["../../../../../../rtp/src/srtp/cipher/ctr.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createCipheriv,\n createDecipheriv,\n createHmac,\n timingSafeEqual,\n} from \"crypto\";\n\nimport { CipherAesBase } from \".\";\nimport type { RtcpHeader } from \"../../rtcp/header\";\nimport type { RtpHeader } from \"../../rtp/rtp\";\nimport { SrtpAuthenticationError } from \"../error\";\nimport {\n finalizeSrtpRtpHeader,\n parseSrtcpHeader,\n parseSrtpRtpHeader,\n} from \"../packet\";\n\nexport class CipherAesCtr extends CipherAesBase {\n readonly authTagLength = 10;\n\n constructor(\n srtpSessionKey: Buffer,\n srtpSessionSalt: Buffer,\n srtcpSessionKey: Buffer,\n srtcpSessionSalt: Buffer,\n private srtpSessionAuthTag: Buffer,\n private srtcpSessionAuthTag: Buffer,\n ) {\n super(srtpSessionKey, srtpSessionSalt, srtcpSessionKey, srtcpSessionSalt);\n }\n\n encryptRtp(header: RtpHeader, payload: Buffer, rolloverCounter: number) {\n const headerBuffer = header.serialize(header.serializeSize);\n\n const counter = this.generateCounter(\n header.sequenceNumber,\n rolloverCounter,\n header.ssrc,\n this.srtpSessionSalt,\n );\n\n const cipher = createCipheriv(\"aes-128-ctr\", this.srtpSessionKey, counter);\n const enc = cipher.update(payload);\n\n const authTag = this.generateSrtpAuthTag(\n rolloverCounter,\n headerBuffer,\n enc,\n );\n return Buffer.concat([headerBuffer, enc, authTag]);\n }\n\n decryptRtp(\n cipherText: Buffer,\n rolloverCounter: number,\n header = parseSrtpRtpHeader(cipherText, this.authTagLength),\n ): [Buffer, RtpHeader] {\n const authTagOffset = cipherText.length - this.authTagLength;\n const encryptedPacket = cipherText.subarray(0, authTagOffset);\n const actualAuthTag = cipherText.subarray(authTagOffset);\n\n const expectedAuthTag = this.generateSrtpAuthTag(\n rolloverCounter,\n encryptedPacket.subarray(0, header.payloadOffset),\n encryptedPacket.subarray(header.payloadOffset),\n );\n assertAuthTag(\n actualAuthTag,\n expectedAuthTag,\n \"Failed to authenticate SRTP packet\",\n );\n\n const counter = this.generateCounter(\n header.sequenceNumber,\n rolloverCounter,\n header.ssrc,\n this.srtpSessionSalt,\n );\n const cipher = createDecipheriv(\n \"aes-128-ctr\",\n this.srtpSessionKey,\n counter,\n );\n const payload = encryptedPacket.subarray(header.payloadOffset);\n const buf = cipher.update(payload);\n\n const dst = Buffer.concat([\n encryptedPacket.subarray(0, header.payloadOffset),\n buf,\n ]);\n\n return [\n dst,\n finalizeSrtpRtpHeader(header, dst, \"Failed to authenticate SRTP packet\"),\n ];\n }\n\n encryptRTCP(rtcpPacket: Buffer, srtcpIndex: number): Buffer {\n let out = Buffer.from(rtcpPacket);\n const ssrc = out.readUInt32BE(4);\n\n const counter = this.generateCounter(\n srtcpIndex & 0xffff,\n srtcpIndex >> 16,\n ssrc,\n this.srtcpSessionSalt,\n );\n const cipher = createCipheriv(\"aes-128-ctr\", this.srtcpSessionKey, counter);\n // Encrypt everything after header\n const buf = cipher.update(out.slice(8));\n buf.copy(out, 8);\n out = Buffer.concat([out, Buffer.alloc(4)]);\n out.writeUInt32BE(srtcpIndex, out.length - 4);\n out[out.length - 4] |= 0x80;\n const authTag = this.generateSrtcpAuthTag(out);\n out = Buffer.concat([out, authTag]);\n\n return out;\n }\n\n decryptRTCP(encrypted: Buffer): [Buffer, RtcpHeader] {\n const header = parseSrtcpHeader(\n encrypted,\n this.authTagLength,\n srtcpIndexSize,\n );\n\n const tailOffset = encrypted.length - (this.authTagLength + srtcpIndexSize);\n const authenticatedPortion = encrypted.subarray(\n 0,\n encrypted.length - this.authTagLength,\n );\n const actualTag = encrypted.subarray(encrypted.length - this.authTagLength);\n const expectedTag = this.generateSrtcpAuthTag(authenticatedPortion);\n assertAuthTag(\n actualTag,\n expectedTag,\n \"Failed to authenticate SRTCP packet\",\n );\n\n const out = Buffer.from(encrypted).slice(0, tailOffset);\n\n const isEncrypted = encrypted[tailOffset] >>> 7;\n if (isEncrypted === 0) return [out, header];\n\n let srtcpIndex = encrypted.readUInt32BE(tailOffset);\n srtcpIndex &= ~(1 << 31);\n\n const ssrc = encrypted.readUInt32BE(4);\n\n const counter = this.generateCounter(\n srtcpIndex & 0xffff,\n srtcpIndex >> 16,\n ssrc,\n this.srtcpSessionSalt,\n );\n const cipher = createDecipheriv(\n \"aes-128-ctr\",\n this.srtcpSessionKey,\n counter,\n );\n const buf = cipher.update(out.subarray(8));\n buf.copy(out, 8);\n return [out, header];\n }\n\n generateSrtcpAuthTag(buf: Buffer) {\n const srtcpSessionAuth = createHmac(\"sha1\", this.srtcpSessionAuthTag);\n return srtcpSessionAuth.update(buf).digest().slice(0, 10);\n }\n\n generateCounter(\n sequenceNumber: number,\n rolloverCounter: number,\n ssrc: number,\n sessionSalt: Buffer,\n ) {\n const counter = Buffer.alloc(16);\n counter.writeUInt32BE(ssrc, 4);\n counter.writeUInt32BE(rolloverCounter, 8);\n counter.writeUInt32BE(Number(BigInt(sequenceNumber) << 16n), 12);\n\n for (let i = 0; i < sessionSalt.length; i++) {\n counter[i] ^= sessionSalt[i];\n }\n return counter;\n }\n\n generateSrtpAuthTag(roc: number, ...buffers: Buffer[]) {\n const srtpSessionAuth = createHmac(\"sha1\", this.srtpSessionAuthTag);\n const rocRaw = Buffer.alloc(4);\n rocRaw.writeUInt32BE(roc);\n\n for (const buf of buffers) {\n srtpSessionAuth.update(buf);\n }\n return srtpSessionAuth.update(rocRaw).digest().subarray(0, 10);\n }\n}\n\nconst srtcpIndexSize = 4;\n\nfunction assertAuthTag(actual: Buffer, expected: Buffer, message: string) {\n if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) {\n throw new SrtpAuthenticationError(message);\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { CipherAesBase } from ".";
2
- import { RtcpHeader } from "../../rtcp/header";
3
- import { RtpHeader } from "../../rtp/rtp";
2
+ import type { RtcpHeader } from "../../rtcp/header";
3
+ import type { RtpHeader } from "../../rtp/rtp";
4
4
  export declare class CipherAesGcm extends CipherAesBase {
5
5
  readonly aeadAuthTagLen = 16;
6
6
  readonly rtpIvWriter: (values: (number | bigint)[]) => Buffer<ArrayBuffer>;
@@ -8,7 +8,7 @@ export declare class CipherAesGcm extends CipherAesBase {
8
8
  readonly aadWriter: (values: (number | bigint)[]) => Buffer<ArrayBuffer>;
9
9
  constructor(srtpSessionKey: Buffer, srtpSessionSalt: Buffer, srtcpSessionKey: Buffer, srtcpSessionSalt: Buffer);
10
10
  encryptRtp(header: RtpHeader, payload: Buffer, rolloverCounter: number): Buffer<ArrayBuffer>;
11
- decryptRtp(cipherText: Buffer, rolloverCounter: number): [Buffer, RtpHeader];
11
+ decryptRtp(cipherText: Buffer, rolloverCounter: number, header?: RtpHeader): [Buffer, RtpHeader];
12
12
  encryptRTCP(rtcpPacket: Buffer, srtcpIndex: number): Buffer;
13
13
  decryptRTCP(encrypted: Buffer): [Buffer, RtcpHeader];
14
14
  private rtpInitializationVector;