Skip to content

Commit

Permalink
fully commented and added some functions
Browse files Browse the repository at this point in the history
  • Loading branch information
THeflinKeeper committed Dec 7, 2023
1 parent aab9661 commit 89ea521
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 33 deletions.
4 changes: 2 additions & 2 deletions keeperapi/src/browser/asn1hex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
return _asnhex_getHexOfV_AtObj(h, idx);
}

// RSA TAGGED
// RSA TAGGED - no changes here
function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
var a = new Array();
var v1 = _asnhex_getStartPosOfV_AtObj(hPrivateKey, 0);
Expand All @@ -278,7 +278,7 @@ function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
return a;
}

// RSA TAGGED
// RSA TAGGED - no changes here
export function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);

Expand Down
47 changes: 33 additions & 14 deletions keeperapi/src/browser/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
CryptoWorkerPoolConfig
} from '../cryptoWorker';

// RSA TAGGED
// RSA TAGGED - just naming the algo
const rsaAlgorithmName: string = "RSASSA-PKCS1-v1_5";
const CBC_IV_LENGTH = 16
const GCM_IV_LENGTH = 12
Expand Down Expand Up @@ -119,7 +119,7 @@ export const browserPlatform: Platform = class {
}
}

// RSA TAGGED
// RSA TAGGED - done, there is already an ecc version
static async importKeyRSA(keyId: string, key: Uint8Array, storage?: KeyStorage): Promise<void> {
keyBytesCache[keyId] = key

Expand Down Expand Up @@ -209,9 +209,14 @@ export const browserPlatform: Platform = class {
await this.importKey(keyId, keyBytes, storage, true)
break
case 'rsa':
// RSA TAGGED
// RSA TAGGED - this seems to be a read operation, keep for now.
// the key should change to ecc at some point up stream instead of here
await this.importKeyRSA(keyId, keyBytes, storage)
break
// TODO: add something like this, need to find pub/priv key pair
// case 'ecc':
// await this.importKeyEC(keyId, keyBytes, keys[keyId].publicKey, storage)
// break
default:
throw new Error(`unable to import ${unwrappedType} key`)
}
Expand Down Expand Up @@ -244,14 +249,14 @@ export const browserPlatform: Platform = class {
static async unwrapKey(key: Uint8Array, keyId: string, unwrappingKeyId: string, encryptionType: EncryptionType, unwrappedKeyType: UnwrappedKeyType, storage?: KeyStorage, canExport?: boolean): Promise<void> {
switch (unwrappedKeyType) {
case 'rsa':
// RSA TAGGED
// RSA TAGGED - added another item for ecc
if (keyBytesCache[keyId]) {
// Skip redundant RSA key decryption
return
}

await this.unwrapRSAKey(key, keyId, unwrappingKeyId, encryptionType, storage)
break
break
case 'aes':
if (cryptoKeysCache['gcm'][keyId]) {
// Keeperapp sometimes provides redundant key data, for example, like if you own a record in a shared folder,
Expand All @@ -261,6 +266,14 @@ export const browserPlatform: Platform = class {

await this.unwrapAesKey(key, keyId, unwrappingKeyId, encryptionType, storage, canExport)
break
// TODO: add something like this, need to find pub/priv key pair
// case 'ecc':
// if (cryptoKeysCache['gcm'][keyId]) {
// return
// }

// await this.unwrapECCKey(key, keyId, unwrappingKeyId, encryptionType, storage, canExport)
// break
default:
throw new Error('Unable to unwrap key type ' + unwrappedKeyType)
}
Expand All @@ -272,7 +285,7 @@ export const browserPlatform: Platform = class {
let algoParams: AesCbcParams | AesGcmParams
switch (encryptionType) {
case 'rsa':
// RSA TAGGED
// RSA TAGGED - ecc already an option, but might need to fallback to ecc here
const rsaKey = await this.loadKeyBytes(unwrappingKeyId, storage)
const keyBytes = this.privateDecrypt(key, rsaKey)
await this.importKey(keyId, keyBytes, storage, canExport)
Expand Down Expand Up @@ -329,12 +342,18 @@ export const browserPlatform: Platform = class {
}
}

// RSA TAGGED
// RSA TAGGED - created copy with ECC involved, unwrapping the private key instead
static async unwrapRSAKey(key: Uint8Array, keyId: string, unwrappingKeyId: string, encryptionType: EncryptionType, storage?: KeyStorage): Promise<void> {
const rsaKey = await this.decrypt(key, unwrappingKeyId, encryptionType, storage)
await this.importKeyRSA(keyId, rsaKey, storage)
}

// keyId: string, privateKey: Uint8Array, publicKey: Uint8Array, storage?: KeyStorage
static async unwrapECCKey(privateKey: Uint8Array, publicKey: Uint8Array, keyId: string, unwrappingKeyId: string, encryptionType: EncryptionType, storage?: KeyStorage): Promise<void> {
const decryptedPrivateKey = await this.decrypt(privateKey, unwrappingKeyId, encryptionType, storage)
await this.importKeyEC(keyId, decryptedPrivateKey, publicKey, storage)
}

static async decrypt(data: Uint8Array, keyId: string, encryptionType: EncryptionType, storage?: KeyStorage): Promise<Uint8Array> {
switch (encryptionType) {
case 'cbc': {
Expand All @@ -346,7 +365,7 @@ export const browserPlatform: Platform = class {
return this.aesGcmDecryptWebCrypto(data, key)
}
case 'rsa': {
// RSA TAGGED
// RSA TAGGED - ecc already an option, but might need to fallback to ecc here
const key = await this.loadKeyBytes(keyId, storage)
return this.privateDecrypt(data, key)
}
Expand All @@ -359,7 +378,7 @@ export const browserPlatform: Platform = class {
}
}

// RSA TAGGED
// RSA TAGGED - ecc copy already below
static async generateRSAKeyPair(): Promise<{privateKey: Uint8Array; publicKey: Uint8Array}> {
let keyPair = await crypto.subtle.generateKey({
name: rsaAlgorithmName,
Expand Down Expand Up @@ -403,7 +422,7 @@ export const browserPlatform: Platform = class {
return await this.mainPublicEncryptEC(messageBytes, pubKey, id, true)
}

// RSA TAGGED
// RSA TAGGED - ecc copy already below
static publicEncrypt(data: Uint8Array, key: string): Uint8Array {
let publicKeyHex = base64ToHex(key);
const pos = _asnhex_getPosArrayOfChildren_AtObj(publicKeyHex, 0);
Expand Down Expand Up @@ -458,7 +477,7 @@ export const browserPlatform: Platform = class {
return await this.mainPublicEncryptEC(data, key, id)
}

// RSA TAGGED
// RSA TAGGED - ecc copy already below
static privateDecrypt(data: Uint8Array, key: Uint8Array): Uint8Array {
let pkh = bytesToHex(key);
const rsa = new RSAKey();
Expand Down Expand Up @@ -546,7 +565,7 @@ export const browserPlatform: Platform = class {
}

// TODO Not tested
// RSA TAGGED
// RSA TAGGED - unused
static async privateSign(data: Uint8Array, key: string): Promise<Uint8Array> {
let _key = await crypto.subtle.importKey("pkcs8",
browserPlatform.base64ToBytes(key),
Expand Down Expand Up @@ -575,7 +594,7 @@ export const browserPlatform: Platform = class {
}

case 'rsa': {
// RSA TAGGED
// RSA TAGGED - ecc already an option, but might need to fallback to ecc here
const publicKey = await this.loadKeyBytes(keyId + '_pub')
return this.publicEncrypt(data, this.bytesToBase64(publicKey))
}
Expand Down Expand Up @@ -969,7 +988,7 @@ type CryptoKeyCache = {
}

// Web crypto supports aes gcm, aes cbc with padding, and ecc
// RSA TAGGED
// RSA TAGGED - just removes rsa type
type CryptoKeyType = Exclude<EncryptionType, 'rsa'>

const cryptoKeysCache: CryptoKeyCache = {
Expand Down
15 changes: 8 additions & 7 deletions keeperapi/src/node/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const nodePlatform: Platform = class {
this.importKey(keyId, privateKey, storage)
}

// RSA TAGGED
// RSA TAGGED - ecc version above
static async importKeyRSA(keyId: string, key: Uint8Array, storage?: KeyStorage): Promise<void> {
this.importKey(keyId, key, storage)
}
Expand Down Expand Up @@ -101,7 +101,7 @@ export const nodePlatform: Platform = class {
unwrappedKey = await nodePlatform.aesGcmDecrypt(key, unwrappingKey)
break;
case 'rsa':
// RSA TAGGED
// RSA TAGGED - ecc version already here, might need to fallback to ecc here
unwrappedKey = await nodePlatform.privateDecrypt(key, unwrappingKey)
break;
case 'ecc':
Expand Down Expand Up @@ -130,7 +130,7 @@ export const nodePlatform: Platform = class {
decrypted = await nodePlatform.aesGcmDecrypt(data, key)
break;
case 'rsa':
// RSA TAGGED
// RSA TAGGED - ecc version already here, might need to fallback to ecc here
decrypted = await nodePlatform.privateDecrypt(data, key)
break;
case 'ecc':
Expand All @@ -142,7 +142,7 @@ export const nodePlatform: Platform = class {
return decrypted
}

// RSA TAGGED
// RSA TAGGED - ecc version already here
static async generateRSAKeyPair(): Promise<{ privateKey: Uint8Array; publicKey: Uint8Array}> {
const rsaKeys = new NodeRSA({b: 2048});
const rsaPublicKey: Buffer = rsaKeys.exportKey('public-der');
Expand Down Expand Up @@ -181,7 +181,7 @@ export const nodePlatform: Platform = class {
encrypted = await nodePlatform.aesGcmEncrypt(data, key)
break;
case 'rsa':
// RSA TAGGED
// RSA TAGGED - ecc version already here, might need to fallback to ecc here
encrypted = nodePlatform.publicEncrypt(data, this.bytesToBase64(key))
break;
case 'ecc':
Expand All @@ -198,6 +198,8 @@ export const nodePlatform: Platform = class {
return this.encrypt(key, wrappingKeyId, encryptionType, storage)
}


// RSA TAGGED - ecc version below
static publicEncrypt(data: Uint8Array, key: string): Uint8Array {
let publicKey = key[0] === '-' // PEM or DER?
? key
Expand All @@ -206,7 +208,6 @@ export const nodePlatform: Platform = class {
type: 'pkcs1',
format: 'der'
})
// RSA TAGGED
return crypto.publicEncrypt({
key: publicKey,
padding: RSA_PKCS1_PADDING
Expand All @@ -228,8 +229,8 @@ export const nodePlatform: Platform = class {
return await this.mainPublicEncryptEC(data, key, id)
}

// RSA TAGGED - ecc version below
static privateDecrypt(data: Uint8Array, key: Uint8Array): Uint8Array {
// RSA TAGGED
return crypto.privateDecrypt({
key: crypto.createPrivateKey({
key: Buffer.from(key),
Expand Down
2 changes: 1 addition & 1 deletion keeperapi/src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export class KeyWrapper {
}
}

export type UnwrappedKeyType = 'aes' | 'rsa'
export type UnwrappedKeyType = 'aes' | 'rsa' | 'ecc'

export type EncryptionType = 'cbc' | 'gcm' | 'rsa' | 'ecc'

Expand Down
52 changes: 43 additions & 9 deletions keeperapi/src/vaultx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,15 +292,40 @@ const processTeams = async (teams: NN<ITeam>[], storage: VaultStorage, dependenc
}
}

// RSA TAGGED
teamPrivateKeys[teamUid + '_priv'] = {
data: team.teamPrivateKey,
dataId: teamUid + '_priv',
keyId: teamUid,
encryptionType: 'cbc',
unwrappedType: 'rsa',
switch (team.teamKeyType) {
case Records.RecordKeyType.ENCRYPTED_BY_DATA_KEY:
teamPrivateKeys[teamUid + '_priv'] = {
data: team.teamPrivateKey,
dataId: teamUid + '_priv',
keyId: teamUid,
encryptionType: 'cbc',
unwrappedType: 'rsa',
}
break
// RSA TAGGED - this essentially changes the unwrapped type to ecc. make sure this is fine
case Records.RecordKeyType.ENCRYPTED_BY_PUBLIC_KEY_ECC:
teamPrivateKeys[teamUid + '_priv'] = {
data: team.teamPrivateKey,
dataId: teamUid + '_priv',
keyId: 'pk_ecc',
encryptionType: 'ecc',
unwrappedType: 'aes',
}
break
default:
console.error(`Key ${team.teamKeyType} type for team folder private key ${teamUid} is not supported for team folder decryption`)
break
}

// RSA TAGGED - fix is the switch case above. need to confirm the encryptionType and unwrappedType are correct
// teamPrivateKeys[teamUid + '_priv'] = {
// data: team.teamPrivateKey,
// dataId: teamUid + '_priv',
// keyId: teamUid,
// encryptionType: 'cbc',
// unwrappedType: 'rsa',
// }

for (const folderKey of team.sharedFolderKeys as NN<ISharedFolderKey>[]) {
// Empty if team being removed from shared folder
if (!folderKey.sharedFolderKey.byteLength) continue
Expand All @@ -319,7 +344,7 @@ const processTeams = async (teams: NN<ITeam>[], storage: VaultStorage, dependenc
unwrappedType: 'aes',
}
break
// RSA TAGGED
// RSA TAGGED - done, since this is a read operation, we only need to add ecc read below
case Records.RecordKeyType.ENCRYPTED_BY_PUBLIC_KEY:
teamSharedFolderKeys[folderUid] = {
data: folderKey.sharedFolderKey,
Expand All @@ -329,6 +354,15 @@ const processTeams = async (teams: NN<ITeam>[], storage: VaultStorage, dependenc
unwrappedType: 'aes',
}
break
case Records.RecordKeyType.ENCRYPTED_BY_PUBLIC_KEY_ECC:
teamSharedFolderKeys[folderUid] = {
data: folderKey.sharedFolderKey,
dataId: folderUid,
keyId: 'pk_ecc',
encryptionType: 'ecc',
unwrappedType: 'aes',
}
break
default:
console.error(`Key ${folderKey.keyType} type for team folder key ${teamUid}/${folderUid} is not supported for team folder decryption`)
break
Expand Down Expand Up @@ -949,7 +983,7 @@ export const syncDown = async (options: SyncDownOptions): Promise<SyncResult> =>

await platform.importKey('data', auth.dataKey!, undefined, true)
await platform.importKeyEC('pk_ecc', new Uint8Array(auth.eccPrivateKey!), new Uint8Array(auth.eccPublicKey!), undefined, true)
// RSA TAGGED
// RSA TAGGED - keep here for read purposes
await platform.importKeyRSA('pk_rsa', auth.privateKey!, undefined, true)

while (true) {
Expand Down

0 comments on commit 89ea521

Please sign in to comment.