Skip to content
This repository has been archived by the owner on Oct 19, 2022. It is now read-only.

Commit

Permalink
Start implementing new encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
Levminer committed Aug 30, 2022
1 parent 8f183d4 commit bf19043
Show file tree
Hide file tree
Showing 11 changed files with 571 additions and 84 deletions.
452 changes: 445 additions & 7 deletions core/Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ auto-launch = "0.3.0"
sysinfo = "0.25.3"
argon2 = "0.4"
rand_core = { version = "0.6", features = ["std"] }
magic-crypt = "3.1.10"
keyring = "1.2.0"

[features]
# by default Tauri runs in production mode
Expand Down
48 changes: 36 additions & 12 deletions core/src/encrypt_password.rs → core/src/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use argon2::{
Argon2,
};

static mut STORED_PASSWORD: String = String::new();
use magic_crypt::{new_magic_crypt, MagicCryptTrait};

extern crate keyring;

#[tauri::command]
pub fn encrypt_password(password: String) -> String {
Expand All @@ -29,25 +31,47 @@ pub fn encrypt_password(password: String) -> String {

#[tauri::command]
pub fn verify_password(password: String, hash: String) -> bool {

let parsed_hash = PasswordHash::new(&hash).unwrap();

let result = Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok();

if result {
unsafe {
STORED_PASSWORD = password;
}
}

result.into()
}

#[tauri::command]
pub fn request_password() -> String {
unsafe {
STORED_PASSWORD.as_str().into()
}
pub fn encrypt_data(key: String, data: String) -> String {
let mc = new_magic_crypt!(key, 256);

let encrypted_string = mc.encrypt_str_to_base64(data);

encrypted_string.into()
}

#[tauri::command]
pub fn decrypt_data(key: String, data: String) -> String {
let mc = new_magic_crypt!(key, 256);

let decrypted_string = mc.decrypt_base64_to_string(data).unwrap();

decrypted_string.into()
}

#[tauri::command]
pub fn set_entry(name: String, data: String) {
let service = "authme_dev";
let entry = keyring::Entry::new(&service, &name);

entry.set_password(data.as_str());
}

#[tauri::command]
pub fn get_entry(name: String) -> String {
let service = "authme_dev";
let entry = keyring::Entry::new(&service, &name);

let item = entry.get_password().unwrap();

item.into()
}
11 changes: 7 additions & 4 deletions core/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use tauri::*;
use window_vibrancy::{apply_mica, apply_vibrancy, NSVisualEffectMaterial};

mod auto_launch;
mod encrypt_password;
mod encryption;
mod system_info;

#[derive(Clone, serde::Serialize)]
Expand Down Expand Up @@ -75,9 +75,12 @@ fn main() {
.invoke_handler(tauri::generate_handler![
auto_launch::auto_launch,
system_info::system_info,
encrypt_password::encrypt_password,
encrypt_password::verify_password,
encrypt_password::request_password
encryption::encrypt_password,
encryption::verify_password,
encryption::encrypt_data,
encryption::decrypt_data,
encryption::set_entry,
encryption::get_entry,
])
.system_tray(make_tray())
.on_system_tray_event(handle_tray_event)
Expand Down
36 changes: 36 additions & 0 deletions interface/libraries/encryption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { invoke } from "@tauri-apps/api"

/**
* Generates random key
*/
export const generateRandomKey = async (): Promise<Buffer> => {
return Buffer.from(window.crypto.getRandomValues(new Uint8Array(32)))
}

/**
* Sets an entry on the system keychain
*/
export const setEntry = async (name: string, data: string) => {
await invoke("set_entry", { name, data })
}

/**
* Gets an entry on the system keychain
*/
export const getEntry = async (name: string): Promise<string> => {
return await invoke("get_entry", { name })
}

/**
* Encrypts a string with the encryption key
*/
export const encryptData = async (key: string, data: string): Promise<string> => {
return await invoke("encrypt_data", { key, data })
}

/**
* Decrypts a string with the encryption key
*/
export const decryptData = async (key: string, data: string): Promise<string> => {
return await invoke("decrypt_data", { key, data })
}
6 changes: 5 additions & 1 deletion interface/libraries/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ declare global {
interface LibState {
authenticated: boolean
importData: null | string
encryptionKey: null | string
}

interface LibSearchQuery {
Expand All @@ -46,7 +47,6 @@ declare global {
security: {
requireAuthentication: null | boolean
password: null | string
key: null | string
}

settings: {
Expand All @@ -67,6 +67,10 @@ declare global {
name: boolean
description: boolean
}

vault: {
codes: null | string
}
}

/** Query selector element types */
Expand Down
9 changes: 6 additions & 3 deletions interface/stores/settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { invoke } from "@tauri-apps/api"
import { writable, get, Writable } from "svelte/store"
import { writable, get } from "svelte/store"
import build from "../../build.json"

const defaultSettings: LibSettings = {
Expand All @@ -12,7 +12,6 @@ const defaultSettings: LibSettings = {
security: {
requireAuthentication: null,
password: null,
key: null,
},

settings: {
Expand All @@ -33,6 +32,10 @@ const defaultSettings: LibSettings = {
name: true,
description: false,
},

vault: {
codes: null,
},
}

const dev = build.dev === "true"
Expand All @@ -41,7 +44,7 @@ if (dev === false && localStorage.settings === undefined) {
invoke("auto_launch")
}

export const settings: Writable<LibSettings> = writable(localStorage.settings ? JSON.parse(localStorage.settings) : defaultSettings)
export const settings = writable<LibSettings>(localStorage.settings ? JSON.parse(localStorage.settings) : defaultSettings)

settings.subscribe((data) => {
console.log("Settings changed: ", data)
Expand Down
5 changes: 3 additions & 2 deletions interface/stores/state.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { writable, get } from "svelte/store"

const defaultState = {
const defaultState: LibState = {
authenticated: false,
importData: null,
encryptionKey: null,
}

export const state = writable(sessionStorage.state ? JSON.parse(sessionStorage.state) : defaultState)
export const state = writable<LibState>(sessionStorage.state ? JSON.parse(sessionStorage.state) : defaultState)

state.subscribe((data) => {
console.log("State changed: ", data)
Expand Down
68 changes: 22 additions & 46 deletions interface/windows/codes/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { textConverter } from "../../libraries/convert"
import { encrypt, decrypt, generateMasterKey } from "../../libraries/auth"
import { TOTP } from "otpauth"
import { dialog, fs, path } from "@tauri-apps/api"
import { dialog, fs } from "@tauri-apps/api"
import { getSettings, setSettings } from "../../stores/settings"
import { generateTimestamp } from "../../libraries/time"
import { getState, setState } from "../../stores/state"
import { decryptData, encryptData } from "interface/libraries/encryption"

const settings = getSettings()
const state = getState()
let codesRefresher: NodeJS.Timer
let searchQuery: LibSearchQuery[] = []
let saveText: string = ""
let savedCodes = false

export const generateCodeElements = (data: LibImportFile) => {
const names = data.names
Expand Down Expand Up @@ -153,8 +152,6 @@ export const generateCodeElements = (data: LibImportFile) => {

generate()

const state = getState()

if (state.importData !== null) {
saveCodes()
}
Expand Down Expand Up @@ -256,7 +253,6 @@ export const search = () => {
}

export const chooseImportFile = async () => {
const state = getState()
const filePath = await dialog.open({ filters: [{ name: "Authme file", extensions: ["authme"] }] })

if (filePath !== null) {
Expand All @@ -276,72 +272,52 @@ export const chooseImportFile = async () => {
}

const saveCodes = async () => {
const password = Buffer.from(settings.security.password, "base64")
const key = Buffer.from(settings.security.key, "base64")

const masterKey = await generateMasterKey(password, key)

const encrypted = await encrypt(saveText, masterKey)

const state = getState()
const encryptionKey = state.encryptionKey
const encryptedText = await encryptData(encryptionKey, saveText)

state.importData = null
settings.vault.codes = encryptedText

setState(state)

const fileContents: LibAuthmeFile = {
codes: encrypted,
encrypted: true,
version: 3,
role: "codes",
date: generateTimestamp(),
}
const filePath = await path.join(await path.configDir(), "Levminer", "Authme 4", "codes", "codes.authme")

await fs.writeTextFile(filePath, JSON.stringify(fileContents, null, "\t"))
setSettings(settings)
}

export const loadCodes = async () => {
const state = getState()
const filePath = await path.join(await path.configDir(), "Levminer", "Authme 4", "codes", "codes.authme")

let file: LibAuthmeFile
searchQuery = []
let savedCodes = false

try {
file = JSON.parse(await fs.readTextFile(filePath))

if (settings.vault.codes !== null) {
// There are saved codes
savedCodes = true
} catch (error) {
} else {
// No saved and no imported codes
document.querySelector(".importCodes").style.display = "block"
document.querySelector(".importingCodes").style.display = "block"
document.querySelector(".gettingStarted").style.display = "block"
}

if (savedCodes === true) {
const password = Buffer.from(settings.security.password, "base64")
const key = Buffer.from(settings.security.key, "base64")

const masterKey = await generateMasterKey(password, key)

const decrypted = await decrypt(file.codes, masterKey)
const encryptionKey = state.encryptionKey
const decryptedText = await decryptData(encryptionKey, settings.vault.codes)

if (state.importData !== null) {
// There are saved and new codes
savedCodes = false
saveText = state.importData + decryptedText

generateCodeElements(textConverter(state.importData + decrypted, settings.settings.sortCodes))

saveText = state.importData + decrypted
generateCodeElements(textConverter(state.importData + decryptedText, settings.settings.sortCodes))
} else {
generateCodeElements(textConverter(decrypted, settings.settings.sortCodes))
// There are saved but not new ones
generateCodeElements(textConverter(decryptedText, settings.settings.sortCodes))
}

document.querySelector<HTMLInputElement>(".search").focus()
} else {
if (state.importData !== null) {
generateCodeElements(textConverter(state.importData, settings.settings.sortCodes))

// There are no saved codes, but new codes imported
saveText = state.importData

generateCodeElements(textConverter(state.importData, settings.settings.sortCodes))
}
}
}
2 changes: 2 additions & 0 deletions interface/windows/confirm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const confirmPassword = async () => {

if (result === true) {
const state = getState()

state.encryptionKey = input
state.authenticated = true
setState(state)

Expand Down
Loading

0 comments on commit bf19043

Please sign in to comment.