mirror of
https://github.com/remotely-save/remotely-save.git
synced 2024-06-07 21:10:45 +00:00
use base64url not base32
This commit is contained in:
parent
792703f8b6
commit
1bc6ba4b01
@ -1,4 +1,4 @@
|
||||
import { base32, base64 } from "rfc4648";
|
||||
import { base32, base64url } from "rfc4648";
|
||||
import {
|
||||
bufferToArrayBuffer,
|
||||
arrayBufferToBuffer,
|
||||
@ -10,6 +10,8 @@ const DEFAULT_ITER = 20000;
|
||||
|
||||
// base32.stringify(Buffer.from('Salted__'))
|
||||
export const MAGIC_ENCRYPTED_PREFIX_BASE32 = "KNQWY5DFMRPV";
|
||||
// base64.stringify(Buffer.from('Salted__'))
|
||||
export const MAGIC_ENCRYPTED_PREFIX_BASE64URL = "U2FsdGVkX";
|
||||
|
||||
const getKeyIVFromPassword = async (
|
||||
salt: Uint8Array,
|
||||
@ -120,7 +122,7 @@ export const encryptStringToBase32 = async (
|
||||
rounds,
|
||||
saltHex
|
||||
);
|
||||
return base32.stringify(new Uint8Array(enc));
|
||||
return base32.stringify(new Uint8Array(enc), { pad: false });
|
||||
};
|
||||
|
||||
export const decryptBase32ToString = async (
|
||||
@ -130,7 +132,36 @@ export const decryptBase32ToString = async (
|
||||
) => {
|
||||
return new TextDecoder().decode(
|
||||
await decryptArrayBuffer(
|
||||
bufferToArrayBuffer(base32.parse(text)),
|
||||
bufferToArrayBuffer(base32.parse(text, { loose: true })),
|
||||
password,
|
||||
rounds
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const encryptStringToBase64url = async (
|
||||
text: string,
|
||||
password: string,
|
||||
rounds: number = DEFAULT_ITER,
|
||||
saltHex: string = ""
|
||||
) => {
|
||||
const enc = await encryptArrayBuffer(
|
||||
bufferToArrayBuffer(new TextEncoder().encode(text)),
|
||||
password,
|
||||
rounds,
|
||||
saltHex
|
||||
);
|
||||
return base64url.stringify(new Uint8Array(enc), { pad: false });
|
||||
};
|
||||
|
||||
export const decryptBase64urlToString = async (
|
||||
text: string,
|
||||
password: string,
|
||||
rounds: number = DEFAULT_ITER
|
||||
) => {
|
||||
return new TextDecoder().decode(
|
||||
await decryptArrayBuffer(
|
||||
bufferToArrayBuffer(base64url.parse(text, { loose: true })),
|
||||
password,
|
||||
rounds
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Vault } from "obsidian";
|
||||
import * as path from "path";
|
||||
|
||||
import { base32 } from "rfc4648";
|
||||
import { base32, base64url } from "rfc4648";
|
||||
import XRegExp from "xregexp";
|
||||
|
||||
/**
|
||||
|
50
src/sync.ts
50
src/sync.ts
@ -14,6 +14,9 @@ import {
|
||||
decryptBase32ToString,
|
||||
encryptStringToBase32,
|
||||
MAGIC_ENCRYPTED_PREFIX_BASE32,
|
||||
decryptBase64urlToString,
|
||||
encryptStringToBase64url,
|
||||
MAGIC_ENCRYPTED_PREFIX_BASE64URL,
|
||||
} from "./encrypt";
|
||||
|
||||
export type SyncStatusType =
|
||||
@ -85,7 +88,7 @@ export const isPasswordOk = async (
|
||||
}
|
||||
const santyCheckKey = remote[0].key;
|
||||
if (santyCheckKey.startsWith(MAGIC_ENCRYPTED_PREFIX_BASE32)) {
|
||||
// this is encrypted!
|
||||
// this is encrypted using old base32!
|
||||
// try to decrypt it using the provided password.
|
||||
if (password === "") {
|
||||
return {
|
||||
@ -96,6 +99,38 @@ export const isPasswordOk = async (
|
||||
try {
|
||||
const res = await decryptBase32ToString(santyCheckKey, password);
|
||||
|
||||
// additional test
|
||||
// because iOS Safari bypasses decryption with wrong password!
|
||||
if (isVaildText(res)) {
|
||||
return {
|
||||
ok: true,
|
||||
reason: "password_matched",
|
||||
} as PasswordCheckType;
|
||||
} else {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "invalid_text_after_decryption",
|
||||
} as PasswordCheckType;
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "password_not_matched",
|
||||
} as PasswordCheckType;
|
||||
}
|
||||
}
|
||||
if (santyCheckKey.startsWith(MAGIC_ENCRYPTED_PREFIX_BASE64URL)) {
|
||||
// this is encrypted using new base64url!
|
||||
// try to decrypt it using the provided password.
|
||||
if (password === "") {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "remote_encrypted_local_no_password",
|
||||
} as PasswordCheckType;
|
||||
}
|
||||
try {
|
||||
const res = await decryptBase64urlToString(santyCheckKey, password);
|
||||
|
||||
// additional test
|
||||
// because iOS Safari bypasses decryption with wrong password!
|
||||
if (isVaildText(res)) {
|
||||
@ -145,7 +180,15 @@ const ensembleMixedStates = async (
|
||||
const remoteEncryptedKey = entry.key;
|
||||
let key = remoteEncryptedKey;
|
||||
if (password !== "") {
|
||||
if (remoteEncryptedKey.startsWith(MAGIC_ENCRYPTED_PREFIX_BASE32)) {
|
||||
key = await decryptBase32ToString(remoteEncryptedKey, password);
|
||||
} else if (
|
||||
remoteEncryptedKey.startsWith(MAGIC_ENCRYPTED_PREFIX_BASE64URL)
|
||||
) {
|
||||
key = await decryptBase64urlToString(remoteEncryptedKey, password);
|
||||
} else {
|
||||
throw Error(`unexpected key=${remoteEncryptedKey}`);
|
||||
}
|
||||
}
|
||||
const backwardMapping = await getSyncMetaMappingByRemoteKey(
|
||||
remoteType,
|
||||
@ -435,7 +478,10 @@ const dispatchOperationToActual = async (
|
||||
if (password !== "") {
|
||||
remoteEncryptedKey = state.remote_encrypted_key;
|
||||
if (remoteEncryptedKey === undefined || remoteEncryptedKey === "") {
|
||||
remoteEncryptedKey = await encryptStringToBase32(key, password);
|
||||
// the old version uses base32
|
||||
// remoteEncryptedKey = await encryptStringToBase32(key, password);
|
||||
// the new version users base64url
|
||||
remoteEncryptedKey = await encryptStringToBase64url(key, password);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user