switched rsa implementation in mobile app

This commit is contained in:
Roland Osborne 2022-12-19 10:53:56 -08:00
parent be43f6829a
commit c99d4b7895
11 changed files with 59 additions and 67 deletions

View File

@ -9,6 +9,8 @@ PODS:
- ReactCommon - ReactCommon
- EXConstants (13.2.4): - EXConstants (13.2.4):
- ExpoModulesCore - ExpoModulesCore
- EXErrorRecovery (3.2.0):
- ExpoModulesCore
- EXFileSystem (14.1.0): - EXFileSystem (14.1.0):
- ExpoModulesCore - ExpoModulesCore
- EXFont (10.2.0): - EXFont (10.2.0):
@ -474,6 +476,7 @@ DEPENDENCIES:
- EXApplication (from `../node_modules/expo-application/ios`) - EXApplication (from `../node_modules/expo-application/ios`)
- EXAV (from `../node_modules/expo-av/ios`) - EXAV (from `../node_modules/expo-av/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`) - EXConstants (from `../node_modules/expo-constants/ios`)
- EXErrorRecovery (from `../node_modules/expo-error-recovery/ios`)
- EXFileSystem (from `../node_modules/expo-file-system/ios`) - EXFileSystem (from `../node_modules/expo-file-system/ios`)
- EXFont (from `../node_modules/expo-font/ios`) - EXFont (from `../node_modules/expo-font/ios`)
- Expo (from `../node_modules/expo`) - Expo (from `../node_modules/expo`)
@ -552,6 +555,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-av/ios" :path: "../node_modules/expo-av/ios"
EXConstants: EXConstants:
:path: "../node_modules/expo-constants/ios" :path: "../node_modules/expo-constants/ios"
EXErrorRecovery:
:path: "../node_modules/expo-error-recovery/ios"
EXFileSystem: EXFileSystem:
:path: "../node_modules/expo-file-system/ios" :path: "../node_modules/expo-file-system/ios"
EXFont: EXFont:
@ -659,6 +664,7 @@ SPEC CHECKSUMS:
EXApplication: e418d737a036e788510f2c4ad6c10a7d54d18586 EXApplication: e418d737a036e788510f2c4ad6c10a7d54d18586
EXAV: 596506c9bee54ad52f2f3b625cdaeb9d9f2dd6b7 EXAV: 596506c9bee54ad52f2f3b625cdaeb9d9f2dd6b7
EXConstants: 7c44785d41d8e959d527d23d29444277a4d1ee73 EXConstants: 7c44785d41d8e959d527d23d29444277a4d1ee73
EXErrorRecovery: 74d71ee59f6814315457b09d68e86aa95cc7d05d
EXFileSystem: 927e0a8885aa9c49e50fc38eaba2c2389f2f1019 EXFileSystem: 927e0a8885aa9c49e50fc38eaba2c2389f2f1019
EXFont: a5d80bd9b3452b2d5abbce2487da89b0150e6487 EXFont: a5d80bd9b3452b2d5abbce2487da89b0150e6487
Expo: fcdb32274e2ca9c7638d3b21b30fb665c6869219 Expo: fcdb32274e2ca9c7638d3b21b30fb665c6869219
@ -674,7 +680,7 @@ SPEC CHECKSUMS:
FirebaseInstallations: 99d24bac0243cf8b0e96cf5426340d211f0bcc80 FirebaseInstallations: 99d24bac0243cf8b0e96cf5426340d211f0bcc80
FirebaseMessaging: 4487bbff9b9b927ba1dd3ea40d1ceb58e4ee3cb5 FirebaseMessaging: 4487bbff9b9b927ba1dd3ea40d1ceb58e4ee3cb5
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f GoogleDataTransport: 1c8145da7117bd68bbbed00cf304edb6a24de00f
GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7 GoogleUtilities: 1d20a6ad97ef46f67bbdec158ce00563a671ebb7
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431

View File

@ -24,7 +24,6 @@
"expo-keep-awake": "~10.2.0", "expo-keep-awake": "~10.2.0",
"expo-splash-screen": "~0.16.2", "expo-splash-screen": "~0.16.2",
"expo-status-bar": "~1.4.0", "expo-status-bar": "~1.4.0",
"jsencrypt": "^3.3.1",
"moment": "^2.29.4", "moment": "^2.29.4",
"react": "18.0.0", "react": "18.0.0",
"react-dom": "18.0.0", "react-dom": "18.0.0",

View File

@ -74,7 +74,7 @@ export function Create() {
)} )}
{ !state.tokenRequired && state.server === 'databag.coredb.org' && ( { !state.tokenRequired && state.server === 'databag.coredb.org' && (
<View style={styles.demo}> <View style={styles.demo}>
<Text style={styles.demoText}>The default public server is to test out the system. Use a private server othersise.</Text> <Text style={styles.demoText}>The default public server is to test out the system. Use a private server othersize.</Text>
</View> </View>
)} )}
</View> </View>

View File

@ -33,8 +33,8 @@ import { removeContactChannelTopic } from 'api/removeContactChannelTopic';
import { getContactChannelNotifications } from 'api/getContactChannelNotifications'; import { getContactChannelNotifications } from 'api/getContactChannelNotifications';
import { setContactChannelNotifications } from 'api/setContactChannelNotifications'; import { setContactChannelNotifications } from 'api/setContactChannelNotifications';
import { RSA } from 'react-native-rsa-native';
import CryptoJS from 'crypto-js'; import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt'
export function useCardContext() { export function useCardContext() {
const [state, setState] = useState({ const [state, setState] = useState({
@ -56,19 +56,21 @@ export function useCardContext() {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const unsealKey = (seals, sealKey) => { const unsealKey = async (seals, sealKey) => {
let unsealedKey; let seal;
if (seals?.length) { if (seals?.length) {
seals.forEach(seal => { seals.forEach(s => {
if (seal.publicKey === sealKey.public) { if (s.publicKey === sealKey.public) {
let crypto = new JSEncrypt(); seal = s;
crypto.setPrivateKey(sealKey.private);
unsealedKey = crypto.decrypt(seal.sealedKey);
} }
}); });
} }
return unsealedKey; if (seal) {
const key = '-----BEGIN RSA PRIVATE KEY-----\n' + sealKey.private + '\n-----END RSA PRIVATE KEY-----'
return await RSA.decrypt(seal.sealedKey, key);
} }
return null;
};
const getCardEntry = (cardId) => { const getCardEntry = (cardId) => {
const card = cards.current.get(cardId); const card = cards.current.get(cardId);
@ -633,7 +635,7 @@ export function useCardContext() {
const card = cards.current.get(cardId); const card = cards.current.get(cardId);
const channel = card.channels.get(channelId); const channel = card.channels.get(channelId);
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.detail.data); const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.detail.data);
const unsealedKey = unsealKey(seals, sealKey); const unsealedKey = await unsealKey(seals, sealKey);
if (unsealedKey) { if (unsealedKey) {
const iv = CryptoJS.enc.Hex.parse(subjectIv); const iv = CryptoJS.enc.Hex.parse(subjectIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey); const key = CryptoJS.enc.Hex.parse(unsealedKey);
@ -660,7 +662,7 @@ export function useCardContext() {
const channel = card.channels.get(channelId); const channel = card.channels.get(channelId);
const { seals } = JSON.parse(channel.detail.data); const { seals } = JSON.parse(channel.detail.data);
const { messageEncrypted, messageIv } = JSON.parse(channel.summary.lastTopic.data); const { messageEncrypted, messageIv } = JSON.parse(channel.summary.lastTopic.data);
const unsealedKey = unsealKey(seals, sealKey); const unsealedKey = await unsealKey(seals, sealKey);
if (unsealedKey) { if (unsealedKey) {
const iv = CryptoJS.enc.Hex.parse(messageIv); const iv = CryptoJS.enc.Hex.parse(messageIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey); const key = CryptoJS.enc.Hex.parse(unsealedKey);

View File

@ -18,8 +18,8 @@ import { clearChannelCard } from 'api/clearChannelCard';
import { addFlag } from 'api/addFlag'; import { addFlag } from 'api/addFlag';
import { setChannelNotifications } from 'api/setChannelNotifications'; import { setChannelNotifications } from 'api/setChannelNotifications';
import { getChannelNotifications } from 'api/getChannelNotifications'; import { getChannelNotifications } from 'api/getChannelNotifications';
import { JSEncrypt } from 'jsencrypt'
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
import { RSA } from 'react-native-rsa-native';
export function useChannelContext() { export function useChannelContext() {
const [state, setState] = useState({ const [state, setState] = useState({
@ -38,18 +38,20 @@ export function useChannelContext() {
setState((s) => ({ ...s, ...value })) setState((s) => ({ ...s, ...value }))
} }
const unsealKey = (seals, sealKey) => { const unsealKey = async (seals, sealKey) => {
let unsealedKey; let seal;
if (seals?.length) { if (seals?.length) {
seals.forEach(seal => { seals.forEach(s => {
if (seal.publicKey === sealKey.public) { if (s.publicKey === sealKey.public) {
let crypto = new JSEncrypt(); seal = s;
crypto.setPrivateKey(sealKey.private);
unsealedKey = crypto.decrypt(seal.sealedKey);
} }
}); });
} }
return unsealedKey if (seal) {
const key = '-----BEGIN RSA PRIVATE KEY-----\n' + sealKey.private + '\n-----END RSA PRIVATE KEY-----'
return await RSA.decrypt(seal.sealedKey, key);
}
return null;
}; };
const setChannel = (channelId, channel) => { const setChannel = (channelId, channel) => {
@ -313,19 +315,15 @@ export function useChannelContext() {
const channel = channels.current.get(channelId); const channel = channels.current.get(channelId);
let { seals, subjectEncrypted, subjectIv } = JSON.parse(channel.detail.data); let { seals, subjectEncrypted, subjectIv } = JSON.parse(channel.detail.data);
seals.forEach(seal => { const unsealedKey = await unsealKey(seals, sealKey);
if (seal.publicKey === sealKey.public) { if (!unsealedKey) {
let crypto = new JSEncrypt(); throw new Error("cannot reseal subject");
crypto.setPrivateKey(sealKey.private); }
const unsealedKey = crypto.decrypt(seal.sealedKey);
const key = CryptoJS.enc.Hex.parse(unsealedKey); const key = CryptoJS.enc.Hex.parse(unsealedKey);
const iv = CryptoJS.lib.WordArray.random(128 / 8); const iv = CryptoJS.lib.WordArray.random(128 / 8);
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ subject }), key, { iv: iv }); const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ subject }), key, { iv: iv });
subjectEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64) subjectEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
subjectIv = iv.toString(); subjectIv = iv.toString();
}
});
const data = { subjectEncrypted, subjectIv, seals }; const data = { subjectEncrypted, subjectIv, seals };
return await setChannelSubject(server, appToken, channelId, 'sealed', data); return await setChannelSubject(server, appToken, channelId, 'sealed', data);
}, },
@ -348,12 +346,12 @@ export function useChannelContext() {
const keyHex = key.toString(); const keyHex = key.toString();
let seals = []; let seals = [];
let crypto = new JSEncrypt(); for (let i = 0; i < keys.length; i++) {
keys.forEach(publicKey => { const publicKey = keys[i];
crypto.setPublicKey(publicKey); const key = '-----BEGIN PUBLIC KEY-----\n' + publicKey + '\n-----END PUBLIC KEY-----'
const sealedKey = crypto.encrypt(keyHex); const sealedKey = await RSA.encrypt(keyHex, key);
seals.push({ publicKey, sealedKey }); seals.push({ publicKey, sealedKey });
}); };
const data = { subjectEncrypted, subjectIv, seals }; const data = { subjectEncrypted, subjectIv, seals };
return await addChannel(server, appToken, 'sealed', data, cards); return await addChannel(server, appToken, 'sealed', data, cards);
@ -391,7 +389,7 @@ export function useChannelContext() {
const { guid } = session.current; const { guid } = session.current;
const channel = channels.current.get(channelId); const channel = channels.current.get(channelId);
const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.detail.data); const { subjectEncrypted, subjectIv, seals } = JSON.parse(channel.detail.data);
const unsealedKey = unsealKey(seals, sealKey); const unsealedKey = await unsealKey(seals, sealKey);
if (unsealedKey) { if (unsealedKey) {
const iv = CryptoJS.enc.Hex.parse(subjectIv); const iv = CryptoJS.enc.Hex.parse(subjectIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey); const key = CryptoJS.enc.Hex.parse(unsealedKey);
@ -416,7 +414,7 @@ export function useChannelContext() {
const channel = channels.current.get(channelId); const channel = channels.current.get(channelId);
const { seals } = JSON.parse(channel.detail.data); const { seals } = JSON.parse(channel.detail.data);
const { messageEncrypted, messageIv } = JSON.parse(channel.summary.lastTopic.data); const { messageEncrypted, messageIv } = JSON.parse(channel.summary.lastTopic.data);
const unsealedKey = unsealKey(seals, sealKey); const unsealedKey = await unsealKey(seals, sealKey);
if (unsealedKey) { if (unsealedKey) {
const iv = CryptoJS.enc.Hex.parse(messageIv); const iv = CryptoJS.enc.Hex.parse(messageIv);
const key = CryptoJS.enc.Hex.parse(unsealedKey); const key = CryptoJS.enc.Hex.parse(unsealedKey);

View File

@ -6,7 +6,6 @@ import { ChannelContext } from 'context/ChannelContext';
import { ProfileContext } from 'context/ProfileContext'; import { ProfileContext } from 'context/ProfileContext';
import moment from 'moment'; import moment from 'moment';
import CryptoJS from 'crypto-js'; import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt'
export function useConversationContext() { export function useConversationContext() {
const [state, setState] = useState({ const [state, setState] = useState({
@ -168,6 +167,14 @@ export function useConversationContext() {
return await channel.actions.setSyncRevision(channelId, revision); return await channel.actions.setSyncRevision(channelId, revision);
} }
useEffect(() => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
const channelItem = getChannel(cardId, channelId);
setChannel(channelItem);
}
}, [card, channel]);
const sync = async () => { const sync = async () => {
const curView = setView.current; const curView = setView.current;
if (!syncing.current) { if (!syncing.current) {

View File

@ -2,7 +2,6 @@ import { useRef, useState, useEffect, useContext } from 'react';
import { ConversationContext } from 'context/ConversationContext'; import { ConversationContext } from 'context/ConversationContext';
import { AccountContext } from 'context/AccountContext'; import { AccountContext } from 'context/AccountContext';
import CryptoJS from 'crypto-js'; import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt'
import { RSA } from 'react-native-rsa-native'; import { RSA } from 'react-native-rsa-native';
export function useConversation() { export function useConversation() {

View File

@ -5,7 +5,6 @@ import { ProfileContext } from 'context/ProfileContext';
import { AccountContext } from 'context/AccountContext'; import { AccountContext } from 'context/AccountContext';
import { AppContext } from 'context/AppContext'; import { AppContext } from 'context/AppContext';
import config from 'constants/Config'; import config from 'constants/Config';
import { JSEncrypt } from 'jsencrypt'
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
import { RSA } from 'react-native-rsa-native'; import { RSA } from 'react-native-rsa-native';
@ -122,8 +121,8 @@ export function useProfileBody() {
}); });
// generate rsa key for sealing channel, delay for activity indicator // generate rsa key for sealing channel, delay for activity indicator
await new Promise(r => setTimeout(r, 1000));
const keys = await RSA.generateKeys(2048); const keys = await RSA.generateKeys(2048);
console.log("NEW KEYS", keys);
// encrypt private key // encrypt private key
const iv = CryptoJS.lib.WordArray.random(128 / 8); const iv = CryptoJS.lib.WordArray.random(128 / 8);

View File

@ -4344,11 +4344,6 @@ jscodeshift@^0.13.1:
temp "^0.8.4" temp "^0.8.4"
write-file-atomic "^2.3.0" write-file-atomic "^2.3.0"
jsencrypt@^3.3.1:
version "3.3.1"
resolved "https://registry.npmjs.org/jsencrypt/-/jsencrypt-3.3.1.tgz"
integrity sha512-dVvV54GdFuJgmEKn+oBiaifDMen4p6o6j/lJh0OVMcouME8sST0bJ7bldIgKBQk4za0zyGn0/pm4vOznR25mLw==
jsesc@^2.5.1: jsesc@^2.5.1:
version "2.5.2" version "2.5.2"
resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"

View File

@ -1,5 +0,0 @@
{
"dependencies": {
"react-native-sqlite-storage": "^6.0.1"
}
}

View File

@ -1,8 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
react-native-sqlite-storage@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/react-native-sqlite-storage/-/react-native-sqlite-storage-6.0.1.tgz#ce6a6b852f07abbea68658d5363818c8bef45dfb"
integrity sha512-1tDFjrint6X6qSYKf3gDyz+XB+X79jfiL6xTugKHPRtF0WvqMtVgdLuNqZunIXjNEvNtNVEbXaeZ6MsguFu00A==