Start working on attachment decryption
This commit is contained in:
parent
845c9865de
commit
69fd89ad6b
@ -3,7 +3,7 @@
|
||||
## Testing
|
||||
|
||||
```sh
|
||||
wget -qO- https://cache.agilebits.com/security-kb/freddy-2013-12-04.tar.gz | tar xvz -
|
||||
wget -qO- https://cache.agilebits.com/security-kb/freddy-2013-12-04.tar.gz | tar xvz
|
||||
mv onepassword_data freddy-2013-12-04.opvault
|
||||
pnpm run test
|
||||
```
|
||||
|
11
src/errors.ts
Normal file
11
src/errors.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export abstract class OPVaultError extends Error {}
|
||||
|
||||
export class AssertionError extends OPVaultError {}
|
||||
|
||||
export class HMACAssertionError extends AssertionError {}
|
||||
|
||||
export function invariant(condition: any, message?: string): asserts condition {
|
||||
if (!condition) {
|
||||
throw new AssertionError(message)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import invariant from "tiny-invariant"
|
||||
import { invariant } from "./errors"
|
||||
|
||||
export enum Category {
|
||||
Login = 1,
|
||||
|
47
src/vault.ts
47
src/vault.ts
@ -1,4 +1,5 @@
|
||||
import * as crypto from "crypto"
|
||||
import { HMACAssertionError, invariant } from "./errors"
|
||||
import type { IFileSystem } from "./fs"
|
||||
import { OnePasswordFileManager } from "./fs"
|
||||
import { i18n } from "./i18n"
|
||||
@ -44,7 +45,9 @@ export class Vault {
|
||||
*/
|
||||
static async of(path: string, profileName = "default", fs: IFileSystem) {
|
||||
const files = new OnePasswordFileManager(fs, path, profileName)
|
||||
const profile = JSON.parse(stripText(await files.getProfile(), "var profile=", ";"))
|
||||
const profile = JSON.parse(
|
||||
stripText(await files.getProfile(), /^var profile\s*=/, ";")
|
||||
)
|
||||
const folders = JSON.parse(stripText(await files.getFolders(), "loadFolders(", ");"))
|
||||
const bands = new Map<string, Band>()
|
||||
|
||||
@ -111,7 +114,7 @@ export class Vault {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove derived keys within the class instance.
|
||||
* Remove derived keys stored within the class instance.
|
||||
*/
|
||||
lock() {
|
||||
this.#master = null!
|
||||
@ -171,6 +174,20 @@ function decryptItem(item: EncryptedItem, master: Cipher): Item {
|
||||
return JSON.parse(detail.toString("utf-8"))
|
||||
}
|
||||
|
||||
function decryptAttachment(item: Buffer, master: Cipher) {
|
||||
invariant(item.slice(0, 7).toString("utf-8") === "OPCLDA")
|
||||
invariant(
|
||||
item.readIntLE(7, 1) === 1,
|
||||
"The version for this attachment file format is not supported."
|
||||
)
|
||||
|
||||
const metadataSize = item.readIntLE(8, 2)
|
||||
const iconSize = item.readIntLE(12, 3)
|
||||
|
||||
const metadata = JSON.parse(item.slice(16, 16 + metadataSize).toString("utf-8"))
|
||||
const icondata = item.slice(16 + metadataSize, 16 + metadataSize + iconSize)
|
||||
}
|
||||
|
||||
/** Encryption and MAC */
|
||||
interface Cipher {
|
||||
/** Encryption key */
|
||||
@ -179,9 +196,27 @@ interface Cipher {
|
||||
hmac: Buffer
|
||||
}
|
||||
|
||||
function stripText(text: string, prefix: string, suffix: string) {
|
||||
if (text.startsWith(prefix)) text = text.slice(prefix.length)
|
||||
if (text.endsWith(suffix)) text = text.slice(0, -suffix.length)
|
||||
function stripText(text: string, prefix: string | RegExp, suffix: string | RegExp) {
|
||||
if (typeof prefix === "string") {
|
||||
if (text.startsWith(prefix)) {
|
||||
text = text.slice(prefix.length)
|
||||
}
|
||||
} else {
|
||||
const prefixMatch = text.match(prefix)
|
||||
if (prefixMatch) {
|
||||
text = text.slice(prefixMatch[0].length)
|
||||
}
|
||||
}
|
||||
if (typeof suffix === "string") {
|
||||
if (text.endsWith(suffix)) {
|
||||
text = text.slice(0, -suffix.length)
|
||||
}
|
||||
} else {
|
||||
const suffixMatch = text.match(suffix)
|
||||
if (suffixMatch) {
|
||||
text = text.slice(0, -suffixMatch[0].length)
|
||||
}
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
@ -190,8 +225,6 @@ const splitPlainText = (derivedKey: Buffer): Cipher => ({
|
||||
hmac: derivedKey.slice(32, 64),
|
||||
})
|
||||
|
||||
class HMACAssertionError extends Error {}
|
||||
|
||||
function decryptOPData(cipherText: Buffer, cipher: Cipher) {
|
||||
const key = cipherText.slice(0, -32)
|
||||
assertHMac(key, cipher.hmac, cipherText.slice(-32))
|
||||
|
Loading…
x
Reference in New Issue
Block a user