1
- import { EncryptionType , KeyStorage , KeyWrapper , LogOptions , Platform , UnwrappedKeyType , CryptoWorkerOptions , UnwrapKeyMap } from '../platform'
1
+ import {
2
+ CryptoWorkerOptions ,
3
+ EncryptionType ,
4
+ KeyStorage ,
5
+ KeyWrapper ,
6
+ LogOptions ,
7
+ Platform ,
8
+ UnwrapKeyMap ,
9
+ UnwrappedKeyType
10
+ } from '../platform'
2
11
import { _asnhex_getHexOfV_AtObj , _asnhex_getPosArrayOfChildren_AtObj } from "./asn1hex" ;
3
12
import { RSAKey } from "./rsa" ;
4
13
import { getKeeperKeys } from "../transmissionKeys" ;
5
14
import { normal64 , normal64Bytes , webSafe64FromBytes } from "../utils" ;
6
15
import { SocketProxy , socketSendMessage } from '../socket'
7
16
import * as asmCrypto from 'asmcrypto.js'
8
17
import type { KeeperHttpResponse } from "../commands" ;
9
- import { CryptoWorker , CryptoWorkerMessage , CryptoWorkerPool , CryptoWorkerPoolConfig , CryptoResults } from '../cryptoWorker' ;
18
+ import {
19
+ CryptoResults ,
20
+ CryptoWorker ,
21
+ CryptoWorkerMessage ,
22
+ CryptoWorkerPool ,
23
+ CryptoWorkerPoolConfig
24
+ } from '../cryptoWorker' ;
10
25
11
26
const rsaAlgorithmName : string = "RSASSA-PKCS1-v1_5" ;
12
27
const CBC_IV_LENGTH = 16
@@ -375,6 +390,11 @@ export const browserPlatform: Platform = class {
375
390
return { publicKey : new Uint8Array ( publicKey ) , privateKey : normal64Bytes ( privateKey . d ! ) }
376
391
}
377
392
393
+ static async publicEncryptECWithHKDF ( message : string | Uint8Array , pubKey : Uint8Array , id : Uint8Array ) : Promise < Uint8Array > {
394
+ const messageBytes = typeof message === "string" ? this . stringToBytes ( message ) : message
395
+ return await this . mainPublicEncryptEC ( messageBytes , pubKey , id , true )
396
+ }
397
+
378
398
static publicEncrypt ( data : Uint8Array , key : string ) : Uint8Array {
379
399
let publicKeyHex = base64ToHex ( key ) ;
380
400
const pos = _asnhex_getPosArrayOfChildren_AtObj ( publicKeyHex , 0 ) ;
@@ -387,23 +407,48 @@ export const browserPlatform: Platform = class {
387
407
return hexToBytes ( encryptedBinary ) ;
388
408
}
389
409
390
- static async publicEncryptEC ( data : Uint8Array , key : Uint8Array , id ?: Uint8Array ) : Promise < Uint8Array > {
410
+ static async mainPublicEncryptEC ( data : Uint8Array , key : Uint8Array , id ?: Uint8Array , useHKDF ?: boolean ) {
391
411
const ephemeralKeyPair = await crypto . subtle . generateKey ( { name : 'ECDH' , namedCurve : 'P-256' } , true , [ 'deriveBits' ] )
392
412
const ephemeralPublicKey = await crypto . subtle . exportKey ( 'raw' , ephemeralKeyPair . publicKey )
393
413
const recipientPublicKey = await crypto . subtle . importKey ( 'raw' , key , { name : 'ECDH' , namedCurve : 'P-256' } , true , [ ] )
394
414
const sharedSecret = await crypto . subtle . deriveBits ( { name : 'ECDH' , public : recipientPublicKey } , ephemeralKeyPair . privateKey , 256 )
395
415
const idBytes = id || new Uint8Array ( )
396
- const sharedSecretCombined = new Uint8Array ( sharedSecret . byteLength + idBytes . byteLength )
397
- sharedSecretCombined . set ( new Uint8Array ( sharedSecret ) , 0 )
398
- sharedSecretCombined . set ( idBytes , sharedSecret . byteLength )
399
- const symmetricKey = await crypto . subtle . digest ( 'SHA-256' , sharedSecretCombined )
416
+ let symmetricKey : ArrayBuffer
417
+ if ( ! useHKDF ) {
418
+ const sharedSecretCombined = new Uint8Array ( sharedSecret . byteLength + idBytes . byteLength )
419
+ sharedSecretCombined . set ( new Uint8Array ( sharedSecret ) , 0 )
420
+ sharedSecretCombined . set ( idBytes , sharedSecret . byteLength )
421
+ symmetricKey = await crypto . subtle . digest ( 'SHA-256' , sharedSecretCombined )
422
+ } else {
423
+ const hkdfKey = await crypto . subtle . importKey (
424
+ 'raw' ,
425
+ sharedSecret ,
426
+ 'HKDF' ,
427
+ false ,
428
+ [ 'deriveBits' ]
429
+ )
430
+ symmetricKey = await crypto . subtle . deriveBits (
431
+ {
432
+ name : 'HKDF' ,
433
+ hash : 'SHA-256' ,
434
+ salt : new Uint8Array ( ) ,
435
+ info : id
436
+ } ,
437
+ hkdfKey ,
438
+ 256
439
+ )
440
+ }
400
441
const cipherText = await this . aesGcmEncrypt ( data , new Uint8Array ( symmetricKey ) )
401
442
const result = new Uint8Array ( ephemeralPublicKey . byteLength + cipherText . byteLength )
402
443
result . set ( new Uint8Array ( ephemeralPublicKey ) , 0 )
403
444
result . set ( new Uint8Array ( cipherText ) , ephemeralPublicKey . byteLength )
404
445
return result
405
446
}
406
447
448
+ static async publicEncryptEC ( data : Uint8Array , key : Uint8Array , id ?: Uint8Array ) : Promise < Uint8Array > {
449
+ return await this . mainPublicEncryptEC ( data , key , id )
450
+ }
451
+
407
452
static privateDecrypt ( data : Uint8Array , key : Uint8Array ) : Uint8Array {
408
453
let pkh = bytesToHex ( key ) ;
409
454
const rsa = new RSAKey ( ) ;
@@ -413,14 +458,14 @@ export const browserPlatform: Platform = class {
413
458
return hexToBytes ( decryptedBinary ) ;
414
459
}
415
460
416
- static async privateDecryptEC ( data : Uint8Array , privateKey : Uint8Array , publicKey ?: Uint8Array , id ?: Uint8Array ) : Promise < Uint8Array > {
461
+ static async privateDecryptEC ( data : Uint8Array , privateKey : Uint8Array , publicKey ?: Uint8Array , id ?: Uint8Array , useHKDF ?: boolean ) : Promise < Uint8Array > {
417
462
if ( ! publicKey ) {
418
463
throw Error ( 'Public key is required for EC decryption' )
419
464
}
420
465
421
466
const privateKeyImport = await this . importPrivateKeyEC ( privateKey , publicKey )
422
467
423
- return this . privateDecryptECWebCrypto ( data , privateKeyImport , id )
468
+ return this . privateDecryptECWebCrypto ( data , privateKeyImport , id , useHKDF )
424
469
}
425
470
426
471
static async importPrivateKeyEC ( privateKey : Uint8Array , publicKey : Uint8Array ) {
@@ -447,23 +492,45 @@ export const browserPlatform: Platform = class {
447
492
return await crypto . subtle . importKey ( 'jwk' , jwk , { name : 'ECDH' , namedCurve : 'P-256' } , true , [ 'deriveBits' ] )
448
493
}
449
494
450
- static async deriveSharedSecretKey ( ephemeralPublicKey : Uint8Array , privateKey : CryptoKey , id ?: Uint8Array ) : Promise < CryptoKey > {
495
+ static async deriveSharedSecretKey ( ephemeralPublicKey : Uint8Array , privateKey : CryptoKey , id ?: Uint8Array , useHKDF ?: boolean ) : Promise < CryptoKey > {
451
496
const pubCryptoKey = await crypto . subtle . importKey ( 'raw' , ephemeralPublicKey , { name : 'ECDH' , namedCurve : 'P-256' } , true , [ ] )
452
497
const sharedSecret = await crypto . subtle . deriveBits ( { name : 'ECDH' , public : pubCryptoKey } , privateKey , 256 )
453
- let sharedSecretCombined = new Uint8Array ( sharedSecret . byteLength + ( id ?. byteLength ?? 0 ) )
454
- sharedSecretCombined . set ( new Uint8Array ( sharedSecret ) , 0 )
455
- if ( id ) {
456
- sharedSecretCombined . set ( id , sharedSecret . byteLength )
498
+ if ( ! useHKDF ) {
499
+ let sharedSecretCombined = new Uint8Array ( sharedSecret . byteLength + ( id ?. byteLength ?? 0 ) )
500
+ sharedSecretCombined . set ( new Uint8Array ( sharedSecret ) , 0 )
501
+ if ( id ) {
502
+ sharedSecretCombined . set ( id , sharedSecret . byteLength )
503
+ }
504
+ const symmetricKeyBuffer = await crypto . subtle . digest ( 'SHA-256' , sharedSecretCombined )
505
+ return this . aesGcmImportKey ( new Uint8Array ( symmetricKeyBuffer ) , false )
506
+ } else {
507
+ const hkdfKey = await crypto . subtle . importKey (
508
+ 'raw' ,
509
+ sharedSecret ,
510
+ 'HKDF' ,
511
+ false ,
512
+ [ 'deriveBits' ]
513
+ )
514
+
515
+ const symmetricKeyBuffer = await crypto . subtle . deriveBits (
516
+ {
517
+ name : 'HKDF' ,
518
+ hash : 'SHA-256' ,
519
+ salt : new Uint8Array ( ) ,
520
+ info : id ?? new Uint8Array ( )
521
+ } ,
522
+ hkdfKey ,
523
+ 256
524
+ )
525
+ return this . aesGcmImportKey ( new Uint8Array ( symmetricKeyBuffer ) , false )
457
526
}
458
- const symmetricKeyBuffer = await crypto . subtle . digest ( 'SHA-256' , sharedSecretCombined )
459
- return this . aesGcmImportKey ( new Uint8Array ( symmetricKeyBuffer ) , false )
460
527
}
461
528
462
- static async privateDecryptECWebCrypto ( data : Uint8Array , privateKey : CryptoKey , id ?: Uint8Array ) : Promise < Uint8Array > {
529
+ static async privateDecryptECWebCrypto ( data : Uint8Array , privateKey : CryptoKey , id ?: Uint8Array , useHKDF ?: boolean ) : Promise < Uint8Array > {
463
530
const message = data . slice ( ECC_PUB_KEY_LENGTH )
464
531
const ephemeralPublicKey = data . slice ( 0 , ECC_PUB_KEY_LENGTH )
465
532
466
- const symmetricKey = await this . deriveSharedSecretKey ( ephemeralPublicKey , privateKey , id )
533
+ const symmetricKey = await this . deriveSharedSecretKey ( ephemeralPublicKey , privateKey , id , useHKDF )
467
534
468
535
return await this . aesGcmDecryptWebCrypto ( message , symmetricKey )
469
536
}
0 commit comments