A little duck 🦆 protecting your passwords. The passwords are stored in a folder, acting as a Vault, locally on your filesystem. The vault contains multiple files. Each file represents one passwords. With this file based storing, the passwords can be easily synchronized between multiple devices using a synchronization of your choice.
⚠️ This application was developed by an amateur (me). There is no guarantee that your passwords are safe and secure and there was never done an audit from a third party! Don't use this with real data and use this on your own risk!
The following image show the layout of a vault. It contains two directories entries and groups along with a masterkey. The master-key is encrypted using the master-password of the user.
An entry represents the collection of a username and a password along with other useful information. They are further distributed into a head and a body. The entry head contains non-critical information like the name and an unique identifier of the entry, where the entry body contains all critical information like the password. This distribution allows to load all entries into the application to display them to the user without the need to decrypt the password. The critical information will only be decrypted when it is actually needed by the application.
Entries can be organized in groups. A group can also contain subgroups. The encrypted file of a group currently only contains the name of the group along with it's unique identifier. An encrypted group doesn't know it's children. The children itself knows to which group it belongs to. This strategy prevents synchronization conflicts when adding new entries on two different computers.
The filename of a group or an entry is derived from the unique identifier using sha256
. This prevents leaking information about the content of the file.
For generating random data the ChaCha algorithm is used as a cryptographically strong pseudo number generator (CSPRNG). The generator is seeded using the entropy pool of the operating system.
The Masterkey is generated from random bytes using the ChaChaRNG. This Masterkey is then encrypted using AES with a key derived from the user's master-password. To derive a key from the Password the key-derivation-function (KDF) Argon2 is used. The Salt for the KDF and the Initialization Vector (IV) for the AES encryption are generated by ChaChaRNG too. The encrypted master-key along the the salt and the IV are stored in the Vault.
To protect the master-key in memory, the master-key is encrypted using a memory-key. The memory-key is derived from an 1Mib large chunk of memory, that filled with random bytes from ChaChaRNG, using Argon2. This chunk of memory is protected and locked using mprotect
and mlock
on unix/linux and using VirtualProtect
and VirtualLock
on windows. The size of 1Mib was inspired by VeraCrypt. It was choosen to prevent from recovering the Memkey through cold boot attacks.
When unlocking a vault, the master-key is decrypted using the user's master-password and then encrypted using the memory key. PWDuck supports having multiple vaults unlocked. Each master-key is protected by a different memory-key. Therefore, each unlocked vault has it's own Nonce (number used once) to derive it's own memory-key.
To store the data on the filesystem, the data is serialized into the Rusty Object Notation (RON). This text representation of the data is than encrypted using the master-key of the vault using AES. The encrypted data along with it's IV is than serialized into RON again and stored on the disk. To prevent the password being leaked, by the serialization process into RON, all of the critical information is encrypted before the first serialization. The content of an entry body is therefore encrypted twice.
PWDuck itself is licensed under the MIT license.
However, PWDuck uses dependencies that are licensed under either the same or a different license. The list of all dependencies along with their licenses are listed below.
Dependencies
Apache-2.0 (15): ab_glyph, ab_glyph_rasterizer, approx, clipboard_macos, clipboard_wayland, gethostname, glyph_brush, glyph_brush_draw_cache, glyph_brush_layout, owned_ttf_parser, owned_ttf_parser, spirv_headers, storage-map, winit, xi-unicode
Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT (2): wasi, wasi
Apache-2.0 OR BSD-2-Clause OR MIT (1): wepoll-ffi
Apache-2.0 OR MIT (240): aes, ahash, anyhow, argon2, arrayvec, async-channel, async-executor, async-global-executor, async-io, async-lock, async-mutex, async-std, async-task, async-trait, atomic-waker, autocfg, base64, base64ct, bit-set, bit-vec, bitflags, blake2, block-buffer, block-buffer, block-buffer, block-modes, block-padding, block-padding, blocking, bstr, bumpalo, bumpalo, byte-tools, cache-padded, cc, cfg-expr, cfg-if, cfg-if, chacha20, cipher, cmake, cocoa, cocoa-foundation, concurrent-queue, copyless, core-foundation, core-foundation, core-foundation, core-foundation-sys, core-foundation-sys, core-foundation-sys, core-graphics, core-graphics, core-graphics, core-graphics-types, core-text, cpufeatures, crossbeam-channel, crossbeam-deque, crossbeam-epoch, crossbeam-utils, crypto-common, ctor, cty, d3d12, derivative, digest, digest, digest, dirs, dirs, dirs-next, dirs-sys, dirs-sys-next, downcast-rs, either, euclid, event-listener, fake-simd, fastrand, fixedbitset, float-ord, fnv, font-kit, foreign-types, foreign-types-shared, form_urlencoded, freetype, futures, futures-channel, futures-core, futures-executor, futures-io, futures-lite, futures-macro, futures-sink, futures-task, futures-util, fxhash, getrandom, getrandom, gfx-auxil, gfx-backend-dx11, gfx-backend-dx12, gfx-backend-empty, gfx-backend-gl, gfx-backend-metal, gfx-backend-vulkan, gfx-hal, glam, gloo-timers, glow, gpu-alloc, gpu-alloc-types, gpu-descriptor, gpu-descriptor-types, guillotiere, hashbrown, hashbrown, heck, hermit-abi, hex, ident_case, idna, indexmap, iovec, itertools, jni-sys, jobserver, js-sys, khronos-egl, kv-log-macro, lazy_static, lazycell, libc, linked-hash-map, lock_api, log, longest-increasing-subsequence, maplit, memmap2, memmap2, metal, minimal-lexical, mio-extras, miow, naga, ndk, ndk-glue, ndk-macro, ndk-sys, net2, num-traits, num_cpus, once_cell, opaque-debug, opaque-debug, opener, parking, parking_lot, parking_lot_core, password-hash, pathfinder_geometry, pathfinder_simd, percent-encoding, pest, pest_derive, pest_generator, pest_meta, petgraph, pin-project-lite, pin-utils, pkg-config, polling, ppv-lite86, proc-macro-crate, proc-macro-error, proc-macro-error-attr, proc-macro2, quote, rand, rand_chacha, rand_core, range-alloc, rayon, rayon-core, remove_dir_all, ron, rustc-hash, rustc_version, rusttype, scoped-tls, scopeguard, semver, semver-parser, serde, serde_derive, servo-fontconfig, sha-1, sha2, smallvec, socket2, spirv_cross, static_assertions, svg_fmt, syn, system-deps, tempfile, thiserror, thiserror-impl, thunderdome, toml, ttf-parser, ttf-parser, typenum, ucd-trie, unicode-bidi, unicode-normalization, unicode-segmentation, unicode-xid, url, value-bag, version_check, waker-fn, wasm-bindgen, wasm-bindgen-backend, wasm-bindgen-futures, wasm-bindgen-macro, wasm-bindgen-macro-support, wasm-bindgen-shared, web-sys, winapi, winapi-i686-pc-windows-gnu, winapi-wsapoll, winapi-x86_64-pc-windows-gnu, wio, x11rb, xdg, zeroize, zeroize_derive
Apache-2.0 OR MIT OR Zlib (5): bytemuck, bytemuck_derive, raw-window-handle, tinyvec, tinyvec_macros
BSD-3-Clause (6): fuchsia-zircon, fuchsia-zircon-sys, instant, num_enum, num_enum_derive, subtle
BSL-1.0 (3): clipboard-win, error-code, str-buf
ISC (2): libloading, libloading
MIT (102): andrew, ash, atk-sys, block, cairo-sys-rs, calloop, cfg_aliases, clipboard_x11, core-video-sys, darling, darling_core, darling_macro, dispatch, dlib, dlib, enigo, expat-sys, freetype-sys, gdk-pixbuf-sys, gdk-sys, generic-array, generic-array, getset, gio-sys, glib-sys, gobject-sys, gtk-sys, iced, iced_aw, iced_core, iced_focus, iced_focus_derive, iced_futures, iced_graphics, iced_native, iced_style, iced_web, iced_winit, inplace_it, kernel32-sys, malloc_buf, matches, memoffset, memsec, mio, mocktopus, mocktopus_macros, nix, nix, nix, nom, objc, objc-foundation, objc_exception, objc_id, ordered-float, pango-sys, pw_entropy, pwduck, pwduck_core, pwduck_gui, raw-window-handle, redox_syscall, redox_users, rfd, rlimit, seckey, servo-fontconfig-sys, slab, smithay-client-toolkit, smithay-client-toolkit, smithay-clipboard, strsim, strum, strum_macros, synstructure, tracing, tracing-attributes, tracing-core, twox-hash, version-compare, wayland-client, wayland-client, wayland-commons, wayland-commons, wayland-cursor, wayland-cursor, wayland-protocols, wayland-protocols, wayland-scanner, wayland-scanner, wayland-sys, wayland-sys, wgpu_glyph, which, winapi, winapi-build, window_clipboard, ws2_32-sys, x11-dl, xcursor, xml-rs
MIT AND Apache-2.0 (1): sha256
MIT AND OFL-1.1 (1): iced_wgpu
MIT OR Unlicense (6): byteorder, memchr, regex-automata, same-file, walkdir, winapi-util
MPL-2.0 (5): dodrio, dwrote, wgpu, wgpu-core, wgpu-types Zlib (1): slotmap