You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-23 17:02:25 +03:00
Reinstate v1 support to make this a non-breaking change
Deprecates several experimental types
This commit is contained in:
172
spec/unit/rendezvous/ecdhv1.spec.ts
Normal file
172
spec/unit/rendezvous/ecdhv1.spec.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "../../olm-loader";
|
||||||
|
import { RendezvousFailureReason, RendezvousIntent } from "../../../src/rendezvous";
|
||||||
|
import { MSC3903ECDHPayload, MSC3903ECDHv1RendezvousChannel } from "../../../src/rendezvous/channels";
|
||||||
|
import { decodeBase64 } from "../../../src/crypto/olmlib";
|
||||||
|
import { DummyTransport } from "./DummyTransport";
|
||||||
|
|
||||||
|
function makeTransport(name: string) {
|
||||||
|
return new DummyTransport<any, MSC3903ECDHPayload>(name, { type: "dummy" });
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("ECDHv1", function () {
|
||||||
|
beforeAll(async function () {
|
||||||
|
await global.Olm.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("with crypto", () => {
|
||||||
|
it("initiator wants to sign in", async function () {
|
||||||
|
const aliceTransport = makeTransport("Alice");
|
||||||
|
const bobTransport = makeTransport("Bob");
|
||||||
|
aliceTransport.otherParty = bobTransport;
|
||||||
|
bobTransport.otherParty = aliceTransport;
|
||||||
|
|
||||||
|
// alice is signing in initiates and generates a code
|
||||||
|
const alice = new MSC3903ECDHv1RendezvousChannel(aliceTransport);
|
||||||
|
const aliceCode = await alice.generateCode(RendezvousIntent.LOGIN_ON_NEW_DEVICE);
|
||||||
|
const bob = new MSC3903ECDHv1RendezvousChannel(bobTransport, decodeBase64(aliceCode.rendezvous.key));
|
||||||
|
|
||||||
|
const bobChecksum = await bob.connect();
|
||||||
|
const aliceChecksum = await alice.connect();
|
||||||
|
|
||||||
|
expect(aliceChecksum).toEqual(bobChecksum);
|
||||||
|
|
||||||
|
const message = { key: "xxx" };
|
||||||
|
await alice.send(message);
|
||||||
|
const bobReceive = await bob.receive();
|
||||||
|
expect(bobReceive).toEqual(message);
|
||||||
|
|
||||||
|
await alice.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
await bob.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("initiator wants to reciprocate", async function () {
|
||||||
|
const aliceTransport = makeTransport("Alice");
|
||||||
|
const bobTransport = makeTransport("Bob");
|
||||||
|
aliceTransport.otherParty = bobTransport;
|
||||||
|
bobTransport.otherParty = aliceTransport;
|
||||||
|
|
||||||
|
// alice is signing in initiates and generates a code
|
||||||
|
const alice = new MSC3903ECDHv1RendezvousChannel(aliceTransport);
|
||||||
|
const aliceCode = await alice.generateCode(RendezvousIntent.LOGIN_ON_NEW_DEVICE);
|
||||||
|
const bob = new MSC3903ECDHv1RendezvousChannel(bobTransport, decodeBase64(aliceCode.rendezvous.key));
|
||||||
|
|
||||||
|
const bobChecksum = await bob.connect();
|
||||||
|
const aliceChecksum = await alice.connect();
|
||||||
|
|
||||||
|
expect(aliceChecksum).toEqual(bobChecksum);
|
||||||
|
|
||||||
|
const message = { key: "xxx" };
|
||||||
|
await bob.send(message);
|
||||||
|
const aliceReceive = await alice.receive();
|
||||||
|
expect(aliceReceive).toEqual(message);
|
||||||
|
|
||||||
|
await alice.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
await bob.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("double connect", async function () {
|
||||||
|
const aliceTransport = makeTransport("Alice");
|
||||||
|
const bobTransport = makeTransport("Bob");
|
||||||
|
aliceTransport.otherParty = bobTransport;
|
||||||
|
bobTransport.otherParty = aliceTransport;
|
||||||
|
|
||||||
|
// alice is signing in initiates and generates a code
|
||||||
|
const alice = new MSC3903ECDHv1RendezvousChannel(aliceTransport);
|
||||||
|
const aliceCode = await alice.generateCode(RendezvousIntent.LOGIN_ON_NEW_DEVICE);
|
||||||
|
const bob = new MSC3903ECDHv1RendezvousChannel(bobTransport, decodeBase64(aliceCode.rendezvous.key));
|
||||||
|
|
||||||
|
const bobChecksum = await bob.connect();
|
||||||
|
const aliceChecksum = await alice.connect();
|
||||||
|
|
||||||
|
expect(aliceChecksum).toEqual(bobChecksum);
|
||||||
|
|
||||||
|
expect(alice.connect()).rejects.toThrow();
|
||||||
|
|
||||||
|
await alice.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
await bob.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("closed", async function () {
|
||||||
|
const aliceTransport = makeTransport("Alice");
|
||||||
|
const bobTransport = makeTransport("Bob");
|
||||||
|
aliceTransport.otherParty = bobTransport;
|
||||||
|
bobTransport.otherParty = aliceTransport;
|
||||||
|
|
||||||
|
// alice is signing in initiates and generates a code
|
||||||
|
const alice = new MSC3903ECDHv1RendezvousChannel(aliceTransport);
|
||||||
|
const aliceCode = await alice.generateCode(RendezvousIntent.LOGIN_ON_NEW_DEVICE);
|
||||||
|
const bob = new MSC3903ECDHv1RendezvousChannel(bobTransport, decodeBase64(aliceCode.rendezvous.key));
|
||||||
|
|
||||||
|
const bobChecksum = await bob.connect();
|
||||||
|
const aliceChecksum = await alice.connect();
|
||||||
|
|
||||||
|
expect(aliceChecksum).toEqual(bobChecksum);
|
||||||
|
|
||||||
|
alice.close();
|
||||||
|
|
||||||
|
expect(alice.connect()).rejects.toThrow();
|
||||||
|
expect(alice.send({})).rejects.toThrow();
|
||||||
|
expect(alice.receive()).rejects.toThrow();
|
||||||
|
|
||||||
|
await alice.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
await bob.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("require ciphertext", async function () {
|
||||||
|
const aliceTransport = makeTransport("Alice");
|
||||||
|
const bobTransport = makeTransport("Bob");
|
||||||
|
aliceTransport.otherParty = bobTransport;
|
||||||
|
bobTransport.otherParty = aliceTransport;
|
||||||
|
|
||||||
|
// alice is signing in initiates and generates a code
|
||||||
|
const alice = new MSC3903ECDHv1RendezvousChannel(aliceTransport);
|
||||||
|
const aliceCode = await alice.generateCode(RendezvousIntent.LOGIN_ON_NEW_DEVICE);
|
||||||
|
const bob = new MSC3903ECDHv1RendezvousChannel(bobTransport, decodeBase64(aliceCode.rendezvous.key));
|
||||||
|
|
||||||
|
const bobChecksum = await bob.connect();
|
||||||
|
const aliceChecksum = await alice.connect();
|
||||||
|
|
||||||
|
expect(aliceChecksum).toEqual(bobChecksum);
|
||||||
|
|
||||||
|
// send a message without encryption
|
||||||
|
await aliceTransport.send({ iv: "dummy", ciphertext: "dummy" });
|
||||||
|
expect(bob.receive()).rejects.toThrow();
|
||||||
|
|
||||||
|
await alice.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
await bob.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ciphertext before set up", async function () {
|
||||||
|
const aliceTransport = makeTransport("Alice");
|
||||||
|
const bobTransport = makeTransport("Bob");
|
||||||
|
aliceTransport.otherParty = bobTransport;
|
||||||
|
bobTransport.otherParty = aliceTransport;
|
||||||
|
|
||||||
|
// alice is signing in initiates and generates a code
|
||||||
|
const alice = new MSC3903ECDHv1RendezvousChannel(aliceTransport);
|
||||||
|
await alice.generateCode(RendezvousIntent.LOGIN_ON_NEW_DEVICE);
|
||||||
|
|
||||||
|
await bobTransport.send({ iv: "dummy", ciphertext: "dummy" });
|
||||||
|
|
||||||
|
expect(alice.receive()).rejects.toThrow();
|
||||||
|
|
||||||
|
await alice.cancel(RendezvousFailureReason.Unknown);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
256
src/rendezvous/channels/MSC3903ECDHv1RendezvousChannel.ts
Normal file
256
src/rendezvous/channels/MSC3903ECDHv1RendezvousChannel.ts
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { SAS } from "@matrix-org/olm";
|
||||||
|
|
||||||
|
import {
|
||||||
|
RendezvousError,
|
||||||
|
RendezvousCode,
|
||||||
|
RendezvousIntent,
|
||||||
|
RendezvousChannel,
|
||||||
|
RendezvousTransportDetails,
|
||||||
|
RendezvousTransport,
|
||||||
|
RendezvousFailureReason,
|
||||||
|
} from "..";
|
||||||
|
import { encodeBase64, decodeBase64 } from "../../crypto/olmlib";
|
||||||
|
import { crypto, subtleCrypto, TextEncoder } from "../../crypto/crypto";
|
||||||
|
import { generateDecimalSas } from "../../crypto/verification/SASDecimal";
|
||||||
|
import { UnstableValue } from "../../NamespacedValue";
|
||||||
|
import { EncryptedPayload, MSC3903ECDHPayload, PlainTextPayload } from "./MSC3903ECDHv2RendezvousChannel";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use ECDH_V2 instead
|
||||||
|
*/
|
||||||
|
export const ECDH_V1 = new UnstableValue(
|
||||||
|
"m.rendezvous.v1.curve25519-aes-sha256",
|
||||||
|
"org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256",
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use ECDHv2RendezvousCode instead
|
||||||
|
*/
|
||||||
|
export interface ECDHv1RendezvousCode extends RendezvousCode {
|
||||||
|
rendezvous: {
|
||||||
|
transport: RendezvousTransportDetails;
|
||||||
|
algorithm: typeof ECDH_V1.name | typeof ECDH_V1.altName;
|
||||||
|
key: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function importKey(key: Uint8Array): Promise<CryptoKey> {
|
||||||
|
if (!subtleCrypto) {
|
||||||
|
throw new Error("Web Crypto is not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
const imported = subtleCrypto.importKey("raw", key, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
|
||||||
|
|
||||||
|
return imported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the unstable [MSC3903](https://github.com/matrix-org/matrix-spec-proposals/pull/3903)
|
||||||
|
* X25519/ECDH key agreement based secure rendezvous channel.
|
||||||
|
* Note that this is UNSTABLE and may have breaking changes without notice.
|
||||||
|
*
|
||||||
|
* @deprecated Use MSC3903ECDHv2RendezvousChannel instead. This implementation will be removed.
|
||||||
|
*/
|
||||||
|
export class MSC3903ECDHv1RendezvousChannel<T> implements RendezvousChannel<T> {
|
||||||
|
private olmSAS?: SAS;
|
||||||
|
private ourPublicKey: Uint8Array;
|
||||||
|
private aesKey?: CryptoKey;
|
||||||
|
private connected = false;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private transport: RendezvousTransport<MSC3903ECDHPayload>,
|
||||||
|
private theirPublicKey?: Uint8Array,
|
||||||
|
public onFailure?: (reason: RendezvousFailureReason) => void,
|
||||||
|
) {
|
||||||
|
this.olmSAS = new global.Olm.SAS();
|
||||||
|
this.ourPublicKey = decodeBase64(this.olmSAS.get_pubkey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async generateCode(intent: RendezvousIntent): Promise<ECDHv1RendezvousCode> {
|
||||||
|
if (this.transport.ready) {
|
||||||
|
throw new Error("Code already generated");
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.transport.send({ algorithm: ECDH_V1.name });
|
||||||
|
|
||||||
|
const rendezvous: ECDHv1RendezvousCode = {
|
||||||
|
rendezvous: {
|
||||||
|
algorithm: ECDH_V1.name,
|
||||||
|
key: encodeBase64(this.ourPublicKey),
|
||||||
|
transport: await this.transport.details(),
|
||||||
|
},
|
||||||
|
intent,
|
||||||
|
};
|
||||||
|
|
||||||
|
return rendezvous;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async connect(): Promise<string> {
|
||||||
|
if (this.connected) {
|
||||||
|
throw new Error("Channel already connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.olmSAS) {
|
||||||
|
throw new Error("Channel closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInitiator = !this.theirPublicKey;
|
||||||
|
|
||||||
|
if (isInitiator) {
|
||||||
|
// wait for the other side to send us their public key
|
||||||
|
const rawRes = await this.transport.receive();
|
||||||
|
if (!rawRes) {
|
||||||
|
throw new Error("No response from other device");
|
||||||
|
}
|
||||||
|
const res = rawRes as Partial<PlainTextPayload>;
|
||||||
|
const { key, algorithm } = res;
|
||||||
|
if (!algorithm || !ECDH_V1.matches(algorithm) || !key) {
|
||||||
|
throw new RendezvousError(
|
||||||
|
"Unsupported algorithm: " + algorithm,
|
||||||
|
RendezvousFailureReason.UnsupportedAlgorithm,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.theirPublicKey = decodeBase64(key);
|
||||||
|
} else {
|
||||||
|
// send our public key unencrypted
|
||||||
|
await this.transport.send({
|
||||||
|
algorithm: ECDH_V1.name,
|
||||||
|
key: encodeBase64(this.ourPublicKey),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.connected = true;
|
||||||
|
|
||||||
|
this.olmSAS.set_their_key(encodeBase64(this.theirPublicKey!));
|
||||||
|
|
||||||
|
const initiatorKey = isInitiator ? this.ourPublicKey : this.theirPublicKey!;
|
||||||
|
const recipientKey = isInitiator ? this.theirPublicKey! : this.ourPublicKey;
|
||||||
|
let aesInfo = ECDH_V1.name;
|
||||||
|
aesInfo += `|${encodeBase64(initiatorKey)}`;
|
||||||
|
aesInfo += `|${encodeBase64(recipientKey)}`;
|
||||||
|
|
||||||
|
const aesKeyBytes = this.olmSAS.generate_bytes(aesInfo, 32);
|
||||||
|
|
||||||
|
this.aesKey = await importKey(aesKeyBytes);
|
||||||
|
|
||||||
|
// blank the bytes out to make sure not kept in memory
|
||||||
|
aesKeyBytes.fill(0);
|
||||||
|
|
||||||
|
const rawChecksum = this.olmSAS.generate_bytes(aesInfo, 5);
|
||||||
|
return generateDecimalSas(Array.from(rawChecksum)).join("-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async encrypt(data: T): Promise<MSC3903ECDHPayload> {
|
||||||
|
if (!subtleCrypto) {
|
||||||
|
throw new Error("Web Crypto is not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
const iv = new Uint8Array(32);
|
||||||
|
crypto.getRandomValues(iv);
|
||||||
|
|
||||||
|
const encodedData = new TextEncoder().encode(JSON.stringify(data));
|
||||||
|
|
||||||
|
const ciphertext = await subtleCrypto.encrypt(
|
||||||
|
{
|
||||||
|
name: "AES-GCM",
|
||||||
|
iv,
|
||||||
|
tagLength: 128,
|
||||||
|
},
|
||||||
|
this.aesKey as CryptoKey,
|
||||||
|
encodedData,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
iv: encodeBase64(iv),
|
||||||
|
ciphertext: encodeBase64(ciphertext),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async send(payload: T): Promise<void> {
|
||||||
|
if (!this.olmSAS) {
|
||||||
|
throw new Error("Channel closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.aesKey) {
|
||||||
|
throw new Error("Shared secret not set up");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.transport.send(await this.encrypt(payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async decrypt({ iv, ciphertext }: EncryptedPayload): Promise<Partial<T>> {
|
||||||
|
if (!ciphertext || !iv) {
|
||||||
|
throw new Error("Missing ciphertext and/or iv");
|
||||||
|
}
|
||||||
|
|
||||||
|
const ciphertextBytes = decodeBase64(ciphertext);
|
||||||
|
|
||||||
|
if (!subtleCrypto) {
|
||||||
|
throw new Error("Web Crypto is not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
const plaintext = await subtleCrypto.decrypt(
|
||||||
|
{
|
||||||
|
name: "AES-GCM",
|
||||||
|
iv: decodeBase64(iv),
|
||||||
|
tagLength: 128,
|
||||||
|
},
|
||||||
|
this.aesKey as CryptoKey,
|
||||||
|
ciphertextBytes,
|
||||||
|
);
|
||||||
|
|
||||||
|
return JSON.parse(new TextDecoder().decode(new Uint8Array(plaintext)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async receive(): Promise<Partial<T> | undefined> {
|
||||||
|
if (!this.olmSAS) {
|
||||||
|
throw new Error("Channel closed");
|
||||||
|
}
|
||||||
|
if (!this.aesKey) {
|
||||||
|
throw new Error("Shared secret not set up");
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawData = await this.transport.receive();
|
||||||
|
if (!rawData) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const data = rawData as Partial<EncryptedPayload>;
|
||||||
|
if (data.ciphertext && data.iv) {
|
||||||
|
return this.decrypt(data as EncryptedPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Data received but no ciphertext");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async close(): Promise<void> {
|
||||||
|
if (this.olmSAS) {
|
||||||
|
this.olmSAS.free();
|
||||||
|
this.olmSAS = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async cancel(reason: RendezvousFailureReason): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.transport.cancel(reason);
|
||||||
|
} finally {
|
||||||
|
await this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,8 +29,9 @@ import { encodeUnpaddedBase64, decodeBase64 } from "../../crypto/olmlib";
|
|||||||
import { crypto, subtleCrypto, TextEncoder } from "../../crypto/crypto";
|
import { crypto, subtleCrypto, TextEncoder } from "../../crypto/crypto";
|
||||||
import { generateDecimalSas } from "../../crypto/verification/SASDecimal";
|
import { generateDecimalSas } from "../../crypto/verification/SASDecimal";
|
||||||
import { UnstableValue } from "../../NamespacedValue";
|
import { UnstableValue } from "../../NamespacedValue";
|
||||||
|
import { ECDH_V1 } from "./MSC3903ECDHv1RendezvousChannel";
|
||||||
|
|
||||||
const ECDH = new UnstableValue(
|
const ECDH_V2 = new UnstableValue(
|
||||||
"m.rendezvous.v2.curve25519-aes-sha256",
|
"m.rendezvous.v2.curve25519-aes-sha256",
|
||||||
"org.matrix.msc3903.rendezvous.v2.curve25519-aes-sha256",
|
"org.matrix.msc3903.rendezvous.v2.curve25519-aes-sha256",
|
||||||
);
|
);
|
||||||
@@ -38,7 +39,7 @@ const ECDH = new UnstableValue(
|
|||||||
export interface ECDHv2RendezvousCode extends RendezvousCode {
|
export interface ECDHv2RendezvousCode extends RendezvousCode {
|
||||||
rendezvous: {
|
rendezvous: {
|
||||||
transport: RendezvousTransportDetails;
|
transport: RendezvousTransportDetails;
|
||||||
algorithm: typeof ECDH.name | typeof ECDH.altName;
|
algorithm: typeof ECDH_V2.name | typeof ECDH_V2.altName | typeof ECDH_V1.name | typeof ECDH_V1.altName;
|
||||||
key: string;
|
key: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -46,7 +47,7 @@ export interface ECDHv2RendezvousCode extends RendezvousCode {
|
|||||||
export type MSC3903ECDHPayload = PlainTextPayload | EncryptedPayload;
|
export type MSC3903ECDHPayload = PlainTextPayload | EncryptedPayload;
|
||||||
|
|
||||||
export interface PlainTextPayload {
|
export interface PlainTextPayload {
|
||||||
algorithm: typeof ECDH.name | typeof ECDH.altName;
|
algorithm: typeof ECDH_V2.name | typeof ECDH_V2.altName | typeof ECDH_V1.name | typeof ECDH_V1.altName;
|
||||||
key?: string;
|
key?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,11 +91,11 @@ export class MSC3903ECDHv2RendezvousChannel<T> implements RendezvousChannel<T> {
|
|||||||
throw new Error("Code already generated");
|
throw new Error("Code already generated");
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.transport.send({ algorithm: ECDH.name });
|
await this.transport.send({ algorithm: ECDH_V2.name });
|
||||||
|
|
||||||
const rendezvous: ECDHv2RendezvousCode = {
|
const rendezvous: ECDHv2RendezvousCode = {
|
||||||
rendezvous: {
|
rendezvous: {
|
||||||
algorithm: ECDH.name,
|
algorithm: ECDH_V2.name,
|
||||||
key: encodeUnpaddedBase64(this.ourPublicKey),
|
key: encodeUnpaddedBase64(this.ourPublicKey),
|
||||||
transport: await this.transport.details(),
|
transport: await this.transport.details(),
|
||||||
},
|
},
|
||||||
@@ -123,7 +124,7 @@ export class MSC3903ECDHv2RendezvousChannel<T> implements RendezvousChannel<T> {
|
|||||||
}
|
}
|
||||||
const res = rawRes as Partial<PlainTextPayload>;
|
const res = rawRes as Partial<PlainTextPayload>;
|
||||||
const { key, algorithm } = res;
|
const { key, algorithm } = res;
|
||||||
if (!algorithm || !ECDH.matches(algorithm) || !key) {
|
if (!algorithm || !ECDH_V2.matches(algorithm) || !key) {
|
||||||
throw new RendezvousError(
|
throw new RendezvousError(
|
||||||
"Unsupported algorithm: " + algorithm,
|
"Unsupported algorithm: " + algorithm,
|
||||||
RendezvousFailureReason.UnsupportedAlgorithm,
|
RendezvousFailureReason.UnsupportedAlgorithm,
|
||||||
@@ -134,7 +135,7 @@ export class MSC3903ECDHv2RendezvousChannel<T> implements RendezvousChannel<T> {
|
|||||||
} else {
|
} else {
|
||||||
// send our public key unencrypted
|
// send our public key unencrypted
|
||||||
await this.transport.send({
|
await this.transport.send({
|
||||||
algorithm: ECDH.name,
|
algorithm: ECDH_V2.name,
|
||||||
key: encodeUnpaddedBase64(this.ourPublicKey),
|
key: encodeUnpaddedBase64(this.ourPublicKey),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -145,7 +146,7 @@ export class MSC3903ECDHv2RendezvousChannel<T> implements RendezvousChannel<T> {
|
|||||||
|
|
||||||
const initiatorKey = isInitiator ? this.ourPublicKey : this.theirPublicKey!;
|
const initiatorKey = isInitiator ? this.ourPublicKey : this.theirPublicKey!;
|
||||||
const recipientKey = isInitiator ? this.theirPublicKey! : this.ourPublicKey;
|
const recipientKey = isInitiator ? this.theirPublicKey! : this.ourPublicKey;
|
||||||
let aesInfo = ECDH.name;
|
let aesInfo = ECDH_V2.name;
|
||||||
aesInfo += `|${encodeUnpaddedBase64(initiatorKey)}`;
|
aesInfo += `|${encodeUnpaddedBase64(initiatorKey)}`;
|
||||||
aesInfo += `|${encodeUnpaddedBase64(recipientKey)}`;
|
aesInfo += `|${encodeUnpaddedBase64(recipientKey)}`;
|
||||||
|
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export * from "./MSC3903ECDHv1RendezvousChannel";
|
||||||
export * from "./MSC3903ECDHv2RendezvousChannel";
|
export * from "./MSC3903ECDHv2RendezvousChannel";
|
||||||
|
|||||||
Reference in New Issue
Block a user