Skip to content

Commit 047ef3e

Browse files
committed
some more refactors, consolidate logic
1 parent ffebde4 commit 047ef3e

File tree

3 files changed

+45
-101
lines changed

3 files changed

+45
-101
lines changed

keeperapi/src/configuration.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ export interface VendorConfiguration {
7575

7676
export interface TransmissionKey {
7777
key: Uint8Array
78-
publicKeyId: number
79-
encryptedKey: Uint8Array
78+
publicKeyId: number // rename to ecKeyId?
79+
// TODO: include mlKemKeyId
80+
// encryptedKey: Uint8Array REMOVE
8081
}
8182

8283
export interface QrcMessageKey {

keeperapi/src/endpoint.ts

Lines changed: 37 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -161,36 +161,7 @@ export class KeeperEndpoint {
161161
const payload = 'toBytes' in message ? message.toBytes() : new Uint8Array()
162162
const apiVersion = message.apiVersion || 0
163163

164-
// Determine whether to use QRC or traditional EC encryption
165-
const mlKemPublicKeyId = this.options.deviceConfig.mlKemPublicKeyId || 100
166-
167-
// TODO: consolidate this logic with prepareRequest
168-
// Use QRC to wrap the transmission key
169-
const ecKeyId = this.options.deviceConfig.transmissionKeyId || 7
170-
if (!isAllowedNumber(ecKeyId)) {
171-
throw new Error(`Invalid EC key ID: ${ecKeyId}`)
172-
}
173-
174-
const serverEcPublicKey = platform.keys[ecKeyId]
175-
const serverMlKemPublicKey = platform.mlKemKeys[mlKemPublicKeyId]
176-
177-
if (!serverEcPublicKey) {
178-
throw new Error(`EC public key not found for ID: ${ecKeyId}`)
179-
}
180-
if (!serverMlKemPublicKey) {
181-
throw new Error(`ML-KEM public key not found for ID: ${mlKemPublicKeyId}`)
182-
}
183-
184-
const hpkeTransmissionKey = await generateHpkeTransmissionKey(
185-
this._transmissionKey.key,
186-
mlKemPublicKeyId,
187-
serverEcPublicKey,
188-
serverMlKemPublicKey,
189-
ecKeyId,
190-
true // use optional data
191-
)
192-
193-
const request = await prepareApiRequest(payload, hpkeTransmissionKey, sessionToken, this.locale, apiVersion)
164+
const request = await prepareApiRequest(payload, this._transmissionKey, sessionToken, this.locale, apiVersion)
194165
log(`Calling REST URL: ${this.getUrl(message.path)}`, 'noCR');
195166
const startTime = Date.now()
196167
const response = await platform.post(this.getUrl(message.path), request)
@@ -205,7 +176,7 @@ export class KeeperEndpoint {
205176
console.log("Response code:", response.statusCode);
206177
}
207178
try {
208-
const decrypted = await platform.aesGcmDecrypt(response.data, hpkeTransmissionKey.key) // test still works
179+
const decrypted = await platform.aesGcmDecrypt(response.data, this._transmissionKey.key)
209180
if ('fromBytes' in message) return message.fromBytes(decrypted)
210181
return
211182
} catch {
@@ -287,43 +258,7 @@ export class KeeperEndpoint {
287258

288259
public async prepareRequest(payload: Uint8Array | unknown, sessionToken?: string, apiVersion?: number): Promise<Uint8Array> {
289260
this._transmissionKey = await this.getTransmissionKey()
290-
291-
// Determine whether to use QRC or traditional EC encryption
292-
const mlKemPublicKeyId = this.options.deviceConfig.mlKemPublicKeyId
293-
let requestTransmissionKey: TransmissionKey | TransmissionKeyHpke
294-
295-
if (mlKemPublicKeyId) {
296-
// TODO: consolidate this logic with executeRestInternal
297-
// Use QRC to wrap the transmission key
298-
const ecKeyId = this.options.deviceConfig.transmissionKeyId || 7
299-
if (!isAllowedNumber(ecKeyId)) {
300-
throw new Error(`Invalid EC key ID: ${ecKeyId}`)
301-
}
302-
303-
const serverEcPublicKey = platform.keys[ecKeyId]
304-
const serverMlKemPublicKey = platform.mlKemKeys[mlKemPublicKeyId]
305-
306-
if (!serverEcPublicKey) {
307-
throw new Error(`EC public key not found for ID: ${ecKeyId}`)
308-
}
309-
if (!serverMlKemPublicKey) {
310-
throw new Error(`ML-KEM public key not found for ID: ${mlKemPublicKeyId}`)
311-
}
312-
313-
requestTransmissionKey = await generateHpkeTransmissionKey(
314-
this._transmissionKey.key,
315-
mlKemPublicKeyId,
316-
serverEcPublicKey,
317-
serverMlKemPublicKey,
318-
ecKeyId,
319-
true // use optional data
320-
)
321-
} else {
322-
// Use traditional EC encryption
323-
requestTransmissionKey = this._transmissionKey
324-
}
325-
326-
return prepareApiRequest(payload, requestTransmissionKey, sessionToken, this.locale, apiVersion)
261+
return prepareApiRequest(payload, this._transmissionKey, sessionToken, this.locale, apiVersion)
327262
}
328263

329264
async decryptPushMessage(pushMessageData: Uint8Array): Promise<WssClientResponse> {
@@ -396,9 +331,10 @@ export async function getPushConnectionRequest(messageSessionUid: Uint8Array, tr
396331
return webSafe64FromBytes(apiRequest)
397332
}
398333

334+
// why isn't this on the KeeperEndpoint class?
399335
export async function prepareApiRequest(
400336
payload: Uint8Array | unknown,
401-
transmissionKey: TransmissionKey | TransmissionKeyHpke,
337+
transmissionKey: TransmissionKey,
402338
sessionToken?: string,
403339
locale?: string,
404340
apiVersion?: number
@@ -416,36 +352,40 @@ export async function prepareApiRequest(
416352
let requestPayloadBytes = ApiRequestPayload.encode(requestPayload).finish()
417353
let encryptedRequestPayload = await platform.aesGcmEncrypt(requestPayloadBytes, transmissionKey.key)
418354

419-
// Check if this is a QRC transmission key
420-
const isQrc = 'qrcMessageKey' in transmissionKey;
421-
422-
let apiRequest: Authentication.IApiRequest;
423-
if (isQrc) {
424-
// Use QRC encryption
425-
const qrcKey = transmissionKey as TransmissionKeyHpke;
426-
apiRequest = ApiRequest.create({
427-
qrcMessageKey: {
428-
clientEcPublicKey: qrcKey.qrcMessageKey.clientEcPublicKey,
429-
mlKemEncapsulatedKey: qrcKey.qrcMessageKey.mlKemEncapsulatedKey,
430-
data: qrcKey.qrcMessageKey.data,
431-
msgVersion: qrcKey.qrcMessageKey.msgVersion,
432-
ecKeyId: qrcKey.qrcMessageKey.ecKeyId
433-
},
434-
encryptedPayload: encryptedRequestPayload,
435-
publicKeyId: qrcKey.publicKeyId, // ML-KEM key ID
436-
encryptedTransmissionKey: qrcKey.optionalData || new Uint8Array(0), // Optional data or empty
437-
locale: locale || 'en_US'
438-
});
439-
} else {
440-
// Use traditional EC encryption
441-
apiRequest = ApiRequest.create({
442-
encryptedTransmissionKey: transmissionKey.encryptedKey,
443-
encryptedPayload: encryptedRequestPayload,
444-
publicKeyId: transmissionKey.publicKeyId,
445-
locale: locale || 'en_US'
446-
});
355+
// Use QRC to wrap the transmission key
356+
const mlKemPublicKeyId = 100 // HARD CODED FOR NOW this.options.deviceConfig.mlKemPublicKeyId || 100
357+
const ecKeyId = transmissionKey.publicKeyId
358+
if (!isAllowedNumber(ecKeyId)) {
359+
throw new Error(`Invalid EC key ID: ${ecKeyId}`)
447360
}
448361

362+
const serverEcPublicKey = platform.keys[ecKeyId]
363+
const serverMlKemPublicKey = platform.mlKemKeys[mlKemPublicKeyId]
364+
365+
if (!serverEcPublicKey) {
366+
throw new Error(`EC public key not found for ID: ${ecKeyId}`)
367+
}
368+
if (!serverMlKemPublicKey) {
369+
throw new Error(`ML-KEM public key not found for ID: ${mlKemPublicKeyId}`)
370+
}
371+
372+
const hpkeTransmissionKey = await generateHpkeTransmissionKey(
373+
transmissionKey.key,
374+
mlKemPublicKeyId,
375+
serverEcPublicKey,
376+
serverMlKemPublicKey,
377+
ecKeyId,
378+
true // use optional data
379+
)
380+
381+
const apiRequest = ApiRequest.create({
382+
qrcMessageKey: hpkeTransmissionKey.qrcMessageKey,
383+
encryptedPayload: encryptedRequestPayload,
384+
publicKeyId: hpkeTransmissionKey.publicKeyId, // ML-KEM key ID
385+
encryptedTransmissionKey: hpkeTransmissionKey.optionalData || new Uint8Array(0), // Optional data or empty
386+
locale: locale || 'en_US'
387+
});
388+
449389
return ApiRequest.encode(apiRequest).finish()
450390
}
451391

keeperapi/src/utils.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,16 @@ export function getKeeperAutomatorAdminUrl(host: KeeperHost, forPath: string, au
4747

4848
export async function generateTransmissionKey(keyNumber: AllowedNumbers): Promise<TransmissionKey> {
4949
const transmissionKey = platform.getRandomBytes(32)
50+
// Hmm. Do we switch this to HPKE only?
5051
return {
51-
publicKeyId: keyNumber,
52+
publicKeyId: keyNumber, // TODO: rename to ecKeyId
5253
key: transmissionKey,
53-
encryptedKey: await platform.publicEncryptEC(transmissionKey, platform.keys[keyNumber])
54+
// TODO: add the mlKemKeyId
55+
// encryptedKey: await platform.publicEncryptEC(transmissionKey, platform.keys[keyNumber]) // deprecate this
5456
}
5557
}
5658

59+
// call this instead (is it exported? also, should we just return the protobuf instead?
5760
export async function generateHpkeTransmissionKey(
5861
transmissionKey: Uint8Array,
5962
mlKemKeyId: number,

0 commit comments

Comments
 (0)