Skip to content

Commit

Permalink
Merge pull request #1445 from internxt/feat/switch_to_kyber_enc_index
Browse files Browse the repository at this point in the history
[PB-2666] Use hybrid encryption for private file sharing and remove double base64 encoding on kyber private keys
  • Loading branch information
sg-gs authored Feb 4, 2025
2 parents 05636b1 + 1d8d537 commit f14e5df
Show file tree
Hide file tree
Showing 10 changed files with 578 additions and 43 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@internxt/css-config": "^1.0.2",
"@internxt/inxt-js": "=1.2.21",
"@internxt/lib": "^1.2.0",
"@internxt/sdk": "=1.9.5",
"@internxt/sdk": "=1.9.6",
"@internxt/ui": "^0.0.14",
"@phosphor-icons/react": "^2.1.7",
"@popperjs/core": "^2.11.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ describe('onSubmit', () => {
},
kyber: {
publicKey: keys.kyber.publicKey ?? '',
privateKey: Buffer.from(decryptedPrivateKyberKey).toString('base64'),
privateKey: decryptedPrivateKyberKey,
},
},
appSumoDetails: null,
Expand Down
11 changes: 3 additions & 8 deletions src/app/auth/services/auth.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,7 @@ describe('logIn', () => {
const plainPrivateKeyInBase64 = Buffer.from(
keysService.decryptPrivateKey(mockUser.keys.ecc.privateKey, mockPassword),
).toString('base64');
const plainPrivateKyberKeyInBase64 = Buffer.from(
keysService.decryptPrivateKey(mockUser.keys.kyber.privateKey, mockPassword),
).toString('base64');
const plainPrivateKyberKeyInBase64 = keysService.decryptPrivateKey(mockUser.keys.kyber.privateKey, mockPassword);

const mockClearUser = {
...mockUser,
Expand Down Expand Up @@ -398,9 +396,7 @@ describe('signUp', () => {
const plainPrivateKeyInBase64 = Buffer.from(
keysService.decryptPrivateKey(mockUser.keys.ecc.privateKey, mockPassword),
).toString('base64');
const plainPrivateKyberKeyInBase64 = Buffer.from(
keysService.decryptPrivateKey(mockUser.keys.kyber.privateKey, mockPassword),
).toString('base64');
const plainPrivateKyberKeyInBase64 = keysService.decryptPrivateKey(mockUser.keys.kyber.privateKey, mockPassword);

const mockClearUser = {
...mockUser,
Expand Down Expand Up @@ -599,8 +595,7 @@ describe('Change password', () => {

const privateKyberKeyEncrypted = inputs.keys.encryptedPrivateKyberKey;
const privateKyberKey = keysService.decryptPrivateKey(privateKyberKeyEncrypted, mockNewPassword);
const privateKyberKeyBase64 = Buffer.from(privateKyberKey).toString('base64');
expect(privateKyberKeyBase64).toBe(mockUser.keys.kyber.privateKey);
expect(privateKyberKey).toBe(mockUser.keys.kyber.privateKey);
});

it('changePassword should correctly re-encrypt keys for old users', async () => {
Expand Down
3 changes: 1 addition & 2 deletions src/app/auth/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,7 @@ export const changePassword = async (newPassword: string, currentPassword: strin
let privateKyberKeyEncrypted = '';

if (user.keys?.kyber?.privateKey) {
const privateKyberKey = Buffer.from(user.keys.kyber.privateKey, 'base64').toString();
privateKyberKeyEncrypted = aes.encrypt(privateKyberKey, newPassword, getAesInitFromEnv());
privateKyberKeyEncrypted = aes.encrypt(user.keys.kyber.privateKey, newPassword, getAesInitFromEnv());
}

const usersClient = SdkFactory.getNewApiInstance().createNewUsersClient();
Expand Down
3 changes: 1 addition & 2 deletions src/app/crypto/services/keys.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ export function parseAndDecryptUserKeys(

let privateKyberKey = '';
if (user.keys?.kyber?.privateKey) {
const decryptedPrivateKyberKey = decryptPrivateKey(user.keys.kyber.privateKey, password);
privateKyberKey = Buffer.from(decryptedPrivateKyberKey).toString('base64');
privateKyberKey = decryptPrivateKey(user.keys.kyber.privateKey, password);
}

const publicKey = user.keys?.ecc?.publicKey ?? user.publicKey;
Expand Down
22 changes: 17 additions & 5 deletions src/app/drive/components/ShareInviteDialog/ShareInviteDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ interface UsersToInvite {
email: string;
userRole: string;
publicKey: string;
keys?: {
ecc: string;
kyber: string;
};
isNewUser: boolean;
}

Expand Down Expand Up @@ -71,7 +75,7 @@ const ShareInviteDialog = (props: ShareInviteDialogProps): JSX.Element => {
const isDuplicated = usersToInvite.find((user) => user.email === userInvited.email);

if (!isDuplicated && isValidEmail(userInvitedEmail)) {
const publicKey = await getUserPublicKey(email);
const { publicKey, keys } = await getUserPublicKey(email);

const markUserAsNew = !publicKey;

Expand All @@ -81,7 +85,7 @@ const ShareInviteDialog = (props: ShareInviteDialogProps): JSX.Element => {
}

const unique: Array<UsersToInvite> = [...usersToInvite];
unique.push({ ...userInvited, publicKey });
unique.push({ ...userInvited, publicKey, keys });
setUsersToInvite(unique);
setEmail('');
} else {
Expand All @@ -106,17 +110,23 @@ const ShareInviteDialog = (props: ShareInviteDialogProps): JSX.Element => {
setUsersToInvite(newUserToInvite);
};

const getUserPublicKey = async (email: string): Promise<string> => {
const getUserPublicKey = async (
email: string,
): Promise<{ publicKey: string; keys: { kyber: string; ecc: string } }> => {
let publicKey = '';
let keys = { kyber: '', ecc: '' };
try {
const publicKeyResponse = await userService.getPublicKeyByEmail(email);
publicKey = publicKeyResponse.publicKey;
if (publicKeyResponse.keys) {
keys = publicKeyResponse.keys;
}
} catch (error) {
if ((error as AppError)?.status !== HTTP_CODES.NOT_FOUND) {
errorService.reportError(error);
}
}
return publicKey;
return { publicKey, keys };
};

const processInvites = async (usersToInvite: UsersToInvite[]) => {
Expand All @@ -137,6 +147,7 @@ const ShareInviteDialog = (props: ShareInviteDialogProps): JSX.Element => {
notifyUser,
notificationMessage: messageText,
publicKey: user.publicKey,
keys: user.keys,
isNewUser: user.isNewUser,
}),
),
Expand All @@ -153,7 +164,7 @@ const ShareInviteDialog = (props: ShareInviteDialogProps): JSX.Element => {
let isThereAnyNewUser = newUsersExists;

if (usersList.length === 0 && isValidEmail(email)) {
const publicKey = await getUserPublicKey(email);
const { publicKey, keys } = await getUserPublicKey(email);
if (!publicKey && !preCreateUsers) {
isThereAnyNewUser = true;
}
Expand All @@ -162,6 +173,7 @@ const ShareInviteDialog = (props: ShareInviteDialogProps): JSX.Element => {
userRole,
isNewUser: !publicKey,
publicKey,
keys,
});
}

Expand Down
13 changes: 8 additions & 5 deletions src/app/share/services/share.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export function getSharingRoles(): Promise<Role[]> {

export function inviteUserToSharedFolder(props: ShareFolderWithUserPayload): Promise<SharingInvite> {
const shareClient = SdkFactory.getNewApiInstance().createShareClient();
return shareClient.inviteUserToSharedFolder({ ...props, encryptionAlgorithm: 'ed25519' }).catch((error) => {
return shareClient.inviteUserToSharedFolder({ ...props }).catch((error) => {
throw errorService.castError(error);
});
}
Expand Down Expand Up @@ -590,13 +590,13 @@ export const decryptMnemonic = async (encryptionKey: string): Promise<string | u
const user = localStorageService.getUser();
if (user) {
let decryptedKey;
const privateKey = user.keys?.ecc?.privateKey ?? user.privateKey;
const privateKyberKey = user.keys?.kyber?.privateKey ?? '';
const privateKeyInBase64 = user.keys?.ecc?.privateKey ?? user.privateKey;
const privateKyberKeyInBase64 = user.keys?.kyber?.privateKey ?? '';
try {
decryptedKey = await hybridDecryptMessageWithPrivateKey({
encryptedMessageInBase64: encryptionKey,
privateKeyInBase64: privateKey,
privateKyberKeyInBase64: privateKyberKey,
privateKeyInBase64,
privateKyberKeyInBase64,
});
} catch (err) {
decryptedKey = user.mnemonic;
Expand Down Expand Up @@ -869,6 +869,9 @@ const shareService = {
validateSharingInvitation,
getPublicSharedItemInfo,
getSharedFolderSize,
inviteUserToSharedFolder,
getSharedFolderInvitationsAsInvitedUser,
getSharingRoles,
};

export default shareService;
Loading

0 comments on commit f14e5df

Please sign in to comment.