gokeepasslib

repository·master·Indexed 42 days ago

https://github.com/tobischo/gokeepasslib

A Go library for reading and writing KeePass 2 (.kdbx) files. It provides programmatic interaction with KeePass databases, including management of groups, entries, and credentials. The library supports KDBX versions 3.1, 4.0, and 4.1, and includes utilities for handling binary data, stream encryption (Salsa20, ChaCha20), and various credential types such as passwords and key files.

Tokens
13.4K
Snippets
61
Records
74
Agent score
55%

What's inside gokeepasslib

  1. Install gokeepasslib

    master

    Use go get to retrieve the latest version of the library:

    go get -u github.com/tobischo/gokeepasslib/v3@latest

    Then, include it in your Go code using the following import path:

    import "github.com/tobischo/gokeepasslib/v3"
    go get -u github.com/tobischo/gokeepasslib/v3@latest
  2. Read a KeePass 2 (.kdbx) file

    master

    To read a .kdbx file, you need to create a new database instance, provide credentials, and use a decoder to populate the database object.

    Important Security Note: After decoding, you must call db.UnlockProtectedEntries() to access protected fields (like passwords). Before saving the database back to a file, you must call db.LockProtectedEntries() to ensure passwords are not stored in plaintext in the XML.

    Compatibility Note: While the library can read most KeePass v2 files, it is recommended to use KeePass v2.30 or higher. Files created with this library are expected to be read by KeePass v2.30+.

    package main
    
    import (
        "fmt"
        "github.com/tobischo/gokeepasslib/v3"
        "os"
    )
    
    func main() {
        file, _ := os.Open("examples/reading/example.kdbx")
    
        db := gokeepasslib.NewDatabase()
        db.Credentials = gokeepasslib.NewPasswordCredentials("abcdefg12345678")
        _ = gokeepasslib.NewDecoder(file).Decode(db)
    
        // Unlock protected entries to access sensitive data
        db.UnlockProtectedEntries()
    
        // Accessing data (ensure you perform bounds checking in production)
        entry := db.Content.Root.Groups[0].Groups[0].Entries[0]
        fmt.Println(entry.GetTitle())
        fmt.Println(entry.GetPassword())
    }
  3. Configure KDBX file format versions

    master

    When creating a new database, you can specify the KDBX version using functional options. By default, new databases are created as KDBX 3.1.

    Available Version Options

    • WithDatabaseKDBXVersion3(): Sets version to KDBX 3.1 (Default).
    • WithDatabaseKDBXVersion40(): Sets version to KDBX 4.0.
    • WithDatabaseKDBXVersion41(): Sets version to KDBX 4.1.

    Version Upgrades and Constraints

    • Reading: The library automatically detects the version from the file, so no option is required when reading.
    • Automatic Upgrade: If you set KDBX 4.1-specific elements (like Group.Tags or Entry.PreviousParentGroup) on a KDBX 4.0 database, the library will upgrade the database to KDBX 4.1 during encoding.
    • Upgrade Error: Setting KDBX 4.1-specific elements on a KDBX 3.1 database will cause encoding to return ErrKdbxVersionUpgradeRequired, as the structural changes (like key derivation and binary storage) cannot be handled automatically.
    db := gokeepasslib.NewDatabase(
        gokeepasslib.WithDatabaseKDBXVersion41(),
    )
  4. Initialize KDBX 4.x File Headers

    master

    When creating KDBX 4.x headers, the library automatically generates secure defaults:

    • Cipher: CipherChaCha20
    • Compression: GzipCompressionFlag (1)
    • KDF: Argon2 with default parallelism (2), memory (1MB), and iterations (2).
    • Seeds/IV: Randomly generated MasterSeed (32 bytes) and EncryptionIV (12 bytes).
    • Salt: A randomly generated 32-byte salt for the KDF.
  5. Understand the Entry data structure

    master

    An Entry represents a single item in a KeePass database. Its fields correspond to the KDBX XML schema:

    • UUID: Unique identifier for the entry.
    • Times: TimeData containing creation, modification, and access timestamps.
    • Values: A slice of ValueData containing key-value pairs (e.g., Username, Password, URL).
    • Binaries: References to binary data.
    • AutoType: AutoTypeData containing settings for automated credential entry.
    • CustomData: A slice of CustomData for plugin-specific information.
    • Histories: A list of History objects, each containing previous versions of the entry.
    • QualityCheck & PreviousParentGroup: KDBX 4.1 specific fields.
  6. Initialize KDBX 3.1 File Headers

    master

    When creating KDBX 3.1 headers, the library automatically generates secure defaults:

    • Cipher: CipherAES
    • Compression: GzipCompressionFlag (1)
    • Transform: TransformRounds defaults to 6000.
    • Seeds/IV: Randomly generated MasterSeed (32 bytes), TransformSeed (32 bytes), EncryptionIV (16 bytes), ProtectedStreamKey (32 bytes), and StreamStartBytes (32 bytes).
    • Stream: InnerRandomStreamID defaults to SalsaStreamID.
  7. Use InnerHeader for KDBX v4 features

    master

    The InnerHeader struct is used specifically for KDBX v4 files. It contains cryptographic options and binary data that are not present in older versions. It includes:

    • InnerRandomStreamID: A uint32 identifier.
    • InnerRandomStreamKey: A byte slice for the key.
    • Binaries: A collection of Binaries associated with the header.

    Note that NewContent does not create an InnerHeader by default (as it defaults to KDBX v3.1 compatibility).

  8. How Binary compression and protection work

    master

    The library handles different compression and encryption states for binary data based on the KDBX specification:

    1. KDBX v3.1: Uses Base64 encoding for the Content field and a Compressed flag. If Protected is set to true, the binary is encrypted with the inner stream cipher.
    2. KDBX v4: Does not use Base64 encoding for the Content field.
    3. Stream Protection: If a binary is stream protected (isStreamProtected()), the library follows the KeePass behavior of never compressing the content and ignoring the Compressed flag during reads/writes to avoid conflicts with the stream cipher.

    When calling SetContent, the library automatically applies Gzip compression if Compressed.Bool is true and the binary is not stream protected.

  9. Unlock and Lock protected groups and entries

    master

    The StreamManager provides high-level methods to recursively traverse the database structure to lock or unlock protected content.

    Unlocking (Decrypting content in-place)

    • UnlockProtectedGroups(gs []Group): Recursively unlocks all groups and their nested entries.
    • UnlockProtectedEntry(e *Entry): Unlocks the values within an entry. If the value is marked as protected (Value.Protected.Bool == true), its Content is replaced with the decrypted string.

    Locking (Encrypting content in-place)

    • LockProtectedGroups(gs []Group): Recursively locks all groups and their nested entries.
    • LockProtectedEntry(e *Entry): Locks the values within an entry. If the value is marked as protected, its Content is replaced with the encrypted string via Pack.

    Note on Order: The library handles the groupChildOrder to ensure the stream cipher remains aligned with the XML document order during processing.

    // To decrypt all content in a set of groups:
    streamManager.UnlockProtectedGroups(myGroups)
    
    // To re-encrypt content before saving:
    streamManager.LockProtectedGroups(myGroups)
  10. Handle KDBX version upgrade requirements

    master

    If you attempt to encode a database containing data that requires a higher KDBX version than the current header specifies (e.g., adding Group.Tags to a KDBX 3.1 file), the library may return an ErrKdbxVersionUpgradeRequired error.

    This error occurs because upgrading from 3.1 to 4.x involves structural changes (like key derivation or inner headers) that cannot be performed as a silent side effect of encoding. To fix this, recreate the database using WithDatabaseKDBXVersion41().

  11. Find a Binary by ID in a Binaries collection

    master

    The Binaries type (a slice of Binary) provides a Find(id int) method to locate a specific binary by its integer ID. It returns a pointer to the Binary if found, or nil if no match exists.

    // Find a binary in a collection
    foundBinary := myBinaries.Find(5)
    if foundBinary != nil {
        // use foundBinary
    }
  12. Configure Binary format with BinaryOption

    master

    When adding binaries to a collection, you can use BinaryOption functions to ensure the data adheres to specific KDBX version requirements.

    • WithKDBXv4Binary(binary): Sets the binary for KDBX v4 format (disables compression flag, sets internal isKDBX4 flag).
    • WithKDBXv31Binary(binary): Sets the binary for KDBX v3.1 format (enables compression flag, sets internal isKDBX4 flag).

    Note: While Binaries.Add is deprecated in favor of Database.AddBinary, these options are the standard way to configure Binary struct behavior.

    // Using options with the (deprecated) Binaries.Add method
    // Note: Prefer Database.AddBinary in your application logic
    binaries.Add(data, gokeepasslib.WithKDBXv4Binary)