@tikoci/centrs 0.1.9-next.22 → 0.1.9-next.23

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.
@@ -72,6 +72,7 @@ import {
72
72
  } from "./btest.ts";
73
73
  import {
74
74
  bytesToBigIntBE,
75
+ type EcSrp5Shared,
75
76
  ecSrp5ClientConfirm,
76
77
  ecSrp5ClientShared,
77
78
  ecSrp5Id,
@@ -676,11 +677,13 @@ async function runClientEcSrp5(
676
677
 
677
678
  const challenge = parseServerChallenge(await readAuthFrame(channel));
678
679
  const validator = ecSrp5Id(username, password, challenge.salt);
679
- const shared = ecSrp5ClientShared(
680
- keypair.privateKey,
681
- challenge.serverPublicKey,
682
- keypair.publicKey,
683
- validator,
680
+ const shared = btestShared(
681
+ ecSrp5ClientShared(
682
+ keypair.privateKey,
683
+ challenge.serverPublicKey,
684
+ keypair.publicKey,
685
+ validator,
686
+ ),
684
687
  );
685
688
  const clientCc = ecSrp5ClientConfirm(shared);
686
689
  await channel.write(encodeConfirmation(clientCc));
@@ -782,11 +785,13 @@ async function runServerEcSrp5(
782
785
  );
783
786
  await channel.write(encodeServerChallenge(serverPublicKey, salt));
784
787
 
785
- const shared = ecSrp5ServerShared(
786
- keypair.privateKey,
787
- validatorScalar,
788
- hello.publicKey,
789
- serverPublicKey,
788
+ const shared = btestShared(
789
+ ecSrp5ServerShared(
790
+ keypair.privateKey,
791
+ validatorScalar,
792
+ hello.publicKey,
793
+ serverPublicKey,
794
+ ),
790
795
  );
791
796
  const clientCc = await readAuthFrame(channel);
792
797
  const expectedCc = ecSrp5ClientConfirm(shared);
@@ -799,6 +804,21 @@ async function runServerEcSrp5(
799
804
  return hello.username;
800
805
  }
801
806
 
807
+ /**
808
+ * The shared secret as btest hashes it: `z` without its leading zero bytes
809
+ * (OpenSSL `BN_bn2bin`), where MAC-Telnet's `mtwei.c` pads it to 32
810
+ * (`BN_bn2binpad`), so the shared math in `ec-srp5.ts` keeps 32 bytes.
811
+ *
812
+ * Grounded on CHR 7.24.5 `/tool/bandwidth-server`: over 800 client handshakes,
813
+ * every one whose `z` began with 0x00 (9) failed with the padded form and no
814
+ * other did. Stripped, 600 of 600 verified, 4 of them with a leading zero.
815
+ */
816
+ export function btestShared(shared: EcSrp5Shared): EcSrp5Shared {
817
+ let start = 0;
818
+ while (start < shared.z.length - 1 && shared.z[start] === 0) start++;
819
+ return start === 0 ? shared : { j: shared.j, z: shared.z.subarray(start) };
820
+ }
821
+
802
822
  function ecSrp5RandomSalt(): Uint8Array {
803
823
  return crypto.getRandomValues(new Uint8Array(16));
804
824
  }
@@ -639,6 +639,22 @@ const BARE_BAD_PARAMETER =
639
639
  const BARE_SYNTAX =
640
640
  /^[ \t]*(?:syntax error|bad command name|(?:expected|missing) [a-z]+(?: [a-z]+)*)[^\n]*\(line \d+ column \d+\)/im;
641
641
 
642
+ /**
643
+ * Whether the printed value of `:parse` carries a rejection, by the same
644
+ * position-anchored grammar {@link classifyParseResult} throws on. For probes
645
+ * and censuses that need the verdict as a boolean. On the schema-5 corpus it
646
+ * agrees with the upstream `response_class` on every one of 5,640 channel and
647
+ * legacy observations (#498).
648
+ */
649
+ export function isParseRejection(output: string): boolean {
650
+ return (
651
+ WRAPPED_BAD_PARAMETER.test(output) ||
652
+ BARE_BAD_PARAMETER.test(output) ||
653
+ WRAPPED_BAD_COMMAND.test(output) ||
654
+ BARE_SYNTAX.test(output)
655
+ );
656
+ }
657
+
642
658
  /**
643
659
  * Classify the printed value of `:put [:parse "<cli>"]`. Grounded on CHR 7.23.3
644
660
  * (see GH#230): `:parse` *never* throws — it returns a value whose text carries