Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save 0xdevalias/b803476793b56f7c45e6361799168eb0 to your computer and use it in GitHub Desktop.

Select an option

Save 0xdevalias/b803476793b56f7c45e6361799168eb0 to your computer and use it in GitHub Desktop.
Some notes on Pioneer / AlphaTheta Rekordbox OneLibrary and Device Library Plus `exportLibrary.db` SQLCipher encryption, key obfuscation, and related `master.db` / etc context.

Reverse Engineering Rekordbox OneLibrary / Device Library Plus exportLibrary.db SQLCipher Encryption + Key

Some notes on Pioneer / AlphaTheta Rekordbox OneLibrary and Device Library Plus exportLibrary.db SQLCipher encryption, key obfuscation, and related master.db / etc context.

Table of Contents

TL;DR

What Is It?

  • https://alphatheta.com/en/onelibrary/
    • OneLibrary

    • OneLibrary is a music library format that takes essential DJ performance data – including playlists, cue points, and beatgrids and makes it work across different types of DJ software and hardware from multiple brands.

    • We’re working with other brands to create a world where you can use your music libraries – your creative assets – freely on any type of media or device (file-based music, cloud, streaming, USB, PC, mobile, etc.) and hardware, regardless of the DJ software you use.

  • https://www.lexicondj.com/blog/everything-you-need-to-know-about-device-library-plus-and-more
    • Everything You Need To Know About Device Library Plus (Dec 21st 2023)

    • What is Pioneer's Device Library Plus and why does it matter?

    • Device Library Plus is the exportLibrary.db file on your USB. Just like the main Rekordbox database, it is an encrypted SQLite database. it is a separate file that lives next to the old Device Library database.

    • Normally I would go into detail a bit more about the database file, but it is encrypted and this time I don't have the encryption key so I can't access it. It is probably similar in structure to the main Rekordbox database, and it contains your track info, cues, playlists and more.

Notes / References

  • mixxxdj/mixxx#15556
    • Issue 15556: Add OneLibrary support

  • xsco/libdjinterop#177
    • Issue 177: Add OneLibrary support

  • https://github.com/morizkraemer/fourfour/blob/master/pioneer-usb-writer/reference-code/PIONEER.md
    • Pioneer DeviceSQL & ANLZ Format — Reverse Engineering Notes

    • This document contains technical discoveries about Pioneer's proprietary DeviceSQL format (export.pdb), ANLZ analysis files, and the newer OneLibrary format (exportLibrary.db) that are not publicly documented. These findings were obtained through binary analysis, disassembly, and hardware testing on a CDJ-3000 (firmware 3.19).

      Existing open-source documentation (Deep Symmetry, rekordcrate, Kaitai Struct specs) covers the broad structure. This document focuses on the undocumented details that make or break hardware compatibility — the things that cause "rekordbox database not found" or silent re-analysis on real players.

    • https://github.com/morizkraemer/fourfour/blob/master/pioneer-usb-writer/reference-code/PIONEER.md#9-onelibrary-format-exportlibrarydb
        1. OneLibrary Format (exportLibrary.db)

        OneLibrary (formerly "Device Library Plus") is a new export format introduced in rekordbox 6.8+ and expanded in rekordbox 7.x. It replaces the binary DeviceSQL format (export.pdb) with an encrypted SQLite database for newer hardware. The format was developed by AlphaTheta and adopted by Algoriddim (djay Pro) and Native Instruments (Traktor) for cross-platform DJ library interoperability.

      • The database is encrypted with SQLCipher (SQLite encryption extension). The key is different from the master.db key.

      • Decryption key: r8gddnr4k847830ar6cqzbkk0el6qytmb3trbbx805jm74vez64i5o8fnrqryqls

      • The key is derived from an obfuscated constant in the rekordbox binary

  • https://github.com/dylanljones/pyrekordbox
    • Pyrekordbox is a Python package for interacting with the library and export data of Pioneers Rekordbox DJ Software.

    • https://github.com/dylanljones/pyrekordbox/blob/master/docs/source/formats/devicelib_plus.md

      • Rekordbox Device Library Plus Format

      • Similar to the main database of Rekordbox (master.db), the Device Library Plus is a SQLite database encrypted via the SQLCipher library. Luckily, it appears that the key of the database is not license or machine dependent and all Device Libraries are encrypted with the same key.

      • The database schema is similar to the main Rekordbox database. It contains a selection of tables from the main database, with similar columns and data types.

    • https://github.com/dylanljones/pyrekordbox/blob/master/docs/source/key.md

      • Database key

      • If the automatic key extraction fails the command line interface of pyrekordbox provides a command for downloading the key from known sources and writing it to the cache file

      • Once the key is cached the database can be opened without providing the key. if you obtained the key from another source, you can also pass it to the database handler

      • On MacOS, the key can be extracted using the RekordLocksmith tool

        • https://github.com/Bide-UK/rekordlocksmith
          • RekordLocksmith

          • This tool was developed with the ethos that users should have unfettered access to their own music libraries. If you're looking to make changes to your Rekordbox library, you shouldn't have to navigate through intentionally placed barriers such as encrypted databases and obfuscated keys.

    • GitHub Copilot (GPT 5.4) Repo Exploration RE: DB Encryption Methods and Keys

      Prompt

      How does this project handle the SQLCipher encryption on the main master.db and device library plus exportLibrary.db ?
      
      Where does it get the key for them from?
      
      Etc
      

      Response

      It uses SQLCipher directly via Python, and for the keys it does not derive them from the database files themselves. It either uses a built-in/deobfuscated known key or a cached/user-supplied key, depending on which database you mean.

      Short version

      • master.db: opened through sqlcipher3 + SQLAlchemy pysqlcipher dialect.
        • If you don’t pass a key, pyrekordbox says it will automatically read/use the Rekordbox DB key.
        • In the current code path, the actual unlock call uses deobfuscate(BLOB) when no key is provided.
        • The docs/changelog also mention a cached key mechanism and a download-key CLI fallback for cases where automatic extraction fails.
      • Device Library Plus / exportLibrary.db: also opened through SQLCipher.
        • If you don’t pass a key, it uses a known built-in key via deobfuscate(BLOB).
        • The docs explicitly say this device/export DB key appears to be shared across all Device Library Plus databases, not machine/license dependent.
      • I did not find a separate implementation specifically for a plain “device library” beyond the newer Device Library Plus / exportLibrary.db support in the returned results.
      • I also did not find evidence in the returned results of custom raw PRAGMA key=... handling; instead it passes the key in the SQLAlchemy SQLCipher connection URL.

      How unlocking is implemented

      For both DB types, the project imports sqlcipher3 if available:

      if unlock:
          if not _sqlcipher_available:  # pragma: no cover
              raise ImportError("Could not unlock database: 'sqlcipher3' package not found")
      
          if not key:  # pragma: no cover
              key = deobfuscate(BLOB)
          elif not key.startswith("402fd"):
              # Check if key looks like a valid key
              raise ValueError("The provided database key doesn't look valid!")
      
          # Unlock database and create engine
          logger.debug("Key: %s", key)
          url = f"sqlite+pysqlcipher://:{key}@/{db_path}?"
          engine = create_engine(url, module=sqlite3)

      And similarly for Device Library Plus:

      if unlock:
          if not _sqlcipher_available:  # pragma: no cover
              raise ImportError("Could not unlock database: 'sqlcipher3' package not found")
      
          if not key:  # pragma: no cover
              key = deobfuscate(BLOB)
          elif not key.startswith("r8gd"):
              # Check if key looks like a valid key
              raise ValueError("The provided database key doesn't look valid!")
      
          # Unlock database and create engine
          logger.debug("Key: %s", key)
          url = f"sqlite+pysqlcipher://:{key}@/{db_path}?"
          engine = create_engine(url, module=sqlite3)

      So the practical mechanism is:

      1. import SQLCipher-capable sqlite driver (sqlcipher3)
      2. obtain key
      3. create SQLAlchemy engine with sqlite+pysqlcipher://:{key}@/{db_path}?

      Where the key comes from

      1) master.db

      The docs say the key is automatically read from Rekordbox config / extracted, and if that fails there are fallback paths.

      The class docstring says:

      key : str, optional
          The database key. By default, pyrekordbox automatically reads the database
          key from the Rekordbox v6 configuration file. This parameter is only required
          if the key extraction fails.

      But the constructor unlock snippet currently shown in search results falls back to deobfuscate(BLOB) if key is empty.

      The project docs also document explicit fallback behavior:

      # Database key
      
      If the automatic key extraction fails the command line interface of ``pyrekordbox``
      provides a command for downloading the key from known sources and writing it to the
      cache file:
      ````shell
      python -m pyrekordbox download-key

      Once the key is cached the database can be opened without providing the key. if you obtained the key from another source, you can also pass it to the database handler

      db = Rekordbox6Database(key="<insert key here>")

      or write it to the cache file manually:

      from pyrekordbox.config import write_db6_key_cache
      
      write_db6_key_cache("<insert key here>")  # call once
      db = Rekordbox6Database()
      
      And the changelog clarifies the history:
      
      ```markdown name=CHANGELOG.md url=https://github.com/dylanljones/pyrekordbox/blob/f695541827cc488af267d6ca8a8e0052598d85a0/CHANGELOG.md#L377-L406
      - **add CLI command to download and cache the RB6 db key from the web ([#64](https://github.com/dylanljones/pyrekordbox/issues/64))**  
        Pyrekordbox tries to download the key from projects that have hard-coded the key 
        (see issue [#77](https://github.com/dylanljones/pyrekordbox/issues/77)). If the download was successful it writes it to the cache file.
      
      - **add method for writing the RB6 db key cache manually ([#64](https://github.com/dylanljones/pyrekordbox/issues/64))**  
        If the extraction of the Rekordbox database key fails (>=6.6.5), the user can now write 
        the key manually to the cache file. After updating the cache the database can be opened 
        without providing the key as argument. To make this work pyrekordbox now caches the 
        decrypted key, not the password for decrypting the key.
      

      Interpretation for master.db

      So for master.db, the project’s model seems to be:

      • historically/ideally: extract key from local Rekordbox install/config
      • if that fails: use cached decrypted key
      • if that’s absent: user can
        • pass the key manually,
        • write it to cache manually,
        • or use download-key to fetch from known external sources

      The docs also describe manual extraction from the Rekordbox executable by breaking on sqlite3_key_v2, which confirms the project assumes the real SQLCipher key is present in memory on the local machine:

      6. Click in the disassembly window, then press Ctrl+G to open the Go To Expression box,
         and search for `sqlite3_key_v2` and press OK.
      ...
      11. The dump at the bottom left will move to that address... You should now see the key as a string.

      2) Device Library Plus / exportLibrary.db

      The documentation is much more explicit here:

      # Rekordbox Device Library Plus Format
      
      ...
      Similar to the main database of Rekordbox (``master.db``), the Device Library Plus is a SQLite database
      encrypted via the [SQLCipher](https://www.zetetic.net/sqlcipher/) library.
      Luckily, it appears that the key of the database is not license or machine dependent and all
      Device Libraries are encrypted with the same key.

      And the code uses deobfuscate(BLOB) by default, unless you pass a key explicitly, and it validates that user-supplied keys “look like” the expected format by checking they start with r8gd.

      So for exportLibrary.db, the answer is basically:

      • pyrekordbox uses a known shared key
      • that key is stored in obfuscated form in the project and recovered with deobfuscate(BLOB)
      • user can override it by passing key=...

      Is the key machine-specific?

      According to the project docs:

      • master.db: docs say it “appears” not to be machine/license dependent.
      • Device Library Plus / exportLibrary.db: docs explicitly say all such device libraries appear to use the same key.

      For master.db:

      ## Encryption
      
      The new SQLite database is encrypted which means it can't be used without
      the encryption key.
      ...
      It appears that the key is not license or machine dependent and all
      databases are encrypted with the same key

      One subtle inconsistency worth noting

      There seems to be a bit of tension between:

      • the docstring/docs saying master.db key is automatically read from Rekordbox config/extraction/cache, and
      • the constructor snippet showing default fallback directly to deobfuscate(BLOB).

      That suggests one of:

      • the actual BLOB may itself be sourced from another module/config path,
      • the docs lag the code somewhat,
      • or the search results didn’t include all surrounding imports/constants/helpers.

      I don’t want to overstate that without reading the exact definitions of BLOB, deobfuscate, and the config helpers.

      What I did not conclusively find

      • A distinct older “device library” SQLCipher path separate from Device Library Plus / exportLibrary.db
      • The exact source definition of BLOB
      • The exact implementation of deobfuscate
      • The exact cache file location/format from the snippets returned

      Code-search caveat

      Code search results are limited and may be incomplete. You can inspect more here:

      If you want, I can do a deeper pass and trace:

      1. where BLOB is defined,
      2. how deobfuscate() works,
      3. where the cached master.db key is stored,
      4. and whether the repo currently hardcodes the actual SQLCipher keys or reconstructs them indirectly.
  • https://github.com/chrisle/alphatheta-connect
    • prolink-connect

    • A Typescript / JavaScript library that is able to talk to AlphaTheta ProDJLink enabled DJ equipment

    • AlphaTheta's PRO DJ LINK protocol, unlocked. Consume CDJ states + Retrieve complete track metadata.

    • GitHub Copilot (GPT 5.4) Repo Exploration RE: DB Encryption Methods and Keys

      Prompt

      How does this project handle the SQLCipher encryption on the main master.db and device library plus exportLibrary.db ?
      
      Where does it get the key for them from?
      
      Etc
      

      Response

      It delegates the SQLCipher handling for exportLibrary.db to the external onelibrary-connect package; this repo itself does not appear to implement the decryption logic or derive the key locally.

      What I found:

      • alphatheta-connect added OneLibrary / exportLibrary.db support with SQLCipher encryption in v0.15.0.
      • When loading OneLibrary, it:
        1. fetches PIONEER/rekordbox/exportLibrary.db from the device over NFS,
        2. writes it to a temp file,
        3. opens it via new OneLibraryAdapter(tempFile).
      • The project re-exports getEncryptionKey, openOneLibraryDb, and OneLibraryAdapter directly from onelibrary-connect, which strongly suggests the actual SQLCipher open/key logic lives there, not here.
      • I did not find code in this repo that:
        • issues PRAGMA key,
        • computes the SQLCipher key,
        • references master.db,
        • references device library by that name,
        • or directly manipulates SQLCipher settings.

      Key evidence:

      /**
       * Try to load OneLibrary database (exportLibrary.db).
       */
      #tryLoadOneLibrary = async (
        device: Device,
        slot: DatabaseSlot,
        tx: Telemetry.TelemetrySpan
      ): Promise<{adapter: OneLibraryAdapter; tempFile: string} | null> => {
        const oneLibraryPath = 'PIONEER/rekordbox/exportLibrary.db';
      
        try {
          const dbData = await this.#fetchFileWithFallback(device, slot, oneLibraryPath, tx);
      
          const tempDir = os.tmpdir();
          const tempFile = path.join(tempDir, `prolink-onelibrary-${device.id}-${slot}-${Date.now()}.db`);
          fs.writeFileSync(tempFile, dbData);
      
          const adapter = new OneLibraryAdapter(tempFile);
          return {adapter, tempFile};
        } catch {
          return null;
        }
      };
      /**
       * OneLibrary Database Adapter
       *
       * Re-exports from onelibrary-connect for backward compatibility.
       */
      
      export {
        getEncryptionKey,
        openOneLibraryDb,
        OneLibraryAdapter,
      } from 'onelibrary-connect';
      /**
       * Re-exports from onelibrary-connect
       */
      
      export {
        getEncryptionKey,
        openOneLibraryDb,
        OneLibraryAdapter,
      } from 'onelibrary-connect';
      "dependencies": {
        "@types/better-sqlite3": "^7.6.13",
        "@types/lodash": "^4.17.21",
        "@types/node": "^22.15.29",
        "@types/promise-retry": "^1.1.6",
        "@types/promise-timeout": "^1.3.3",
        "@types/signale": "^1.4.7",
        "async-mutex": "^0.5.0",
        "better-sqlite3-multiple-ciphers": "^12.5.0",
        "iconv-lite": "^0.6.3",
        "ip-address": "^10.1.0",
        "js-xdr": "^3.1.2",
        "kaitai-struct": "^0.11.0",
        "lodash": "^4.17.21",
        "lru_map": "^0.4.1",
        "metadata-connect": "file:../metadata-connect",
        "onelibrary-connect": "file:../onelibrary-connect",
      ### Added
      
      - **Passive monitoring mode**: Monitor Pro DJ Link networks via packet capture (pcap) without joining the network as a virtual CDJ. Allows monitoring alongside rekordbox.
      - **Artwork extraction from audio files via NFS**: Extract album artwork directly from audio files (MP3, FLAC, AIFF, M4A) over NFS when artwork is not available in the rekordbox database.
      - **OneLibrary database support**: Full support for rekordbox 7.x's new OneLibrary format (exportLibrary.db) with SQLCipher encryption, including tracks, playlists, cues, hot cue banks, myTags, and history.
      - **OneLibrary Support** *(new)* - Full support for rekordbox 7.x's new OneLibrary
        format (exportLibrary.db) with SQLCipher encryption, including tracks, playlists,
        cues, hot cue banks, myTags, and history.

      So where does it get the key from?

      From this repo alone: not visible. The only concrete signal is that it re-exports:

      • getEncryptionKey
      • openOneLibraryDb
      • OneLibraryAdapter

      from onelibrary-connect, so the key derivation/retrieval is almost certainly implemented there.

      What about master.db and “device library”?

      I don’t see handling for those in this repository.

      This repo appears to support two DB paths/formats:

      1. Legacy device export DB: PIONEER/rekordbox/export.pdb
        • parsed directly as Pioneer’s PDB format, not SQLCipher.
      2. OneLibrary DB: PIONEER/rekordbox/exportLibrary.db
        • opened through OneLibraryAdapter, which likely handles SQLCipher.

      For comparison, the fallback legacy path is explicit here:

      /**
       * Load PDB database (export.pdb) and hydrate into MetadataORM.
       */
      #loadPdbDatabase = async (
        device: Device,
        slot: DatabaseSlot,
        tx: Telemetry.TelemetrySpan
      ): Promise<MetadataORM> => {
        const pdbPath = 'PIONEER/rekordbox/export.pdb';
        const pdbData = await this.#fetchFileWithFallback(device, slot, pdbPath, tx);
      
        const dbCreateTx = tx.startChild({op: 'setupDatabase'});
        const orm = new MetadataORM();
        dbCreateTx.finish();
      
        await hydrateDatabase({
          orm,
          pdbData,
          span: tx,
          onProgress: progress => this.#emitter.emit('hydrationProgress', {device, slot, progress}),
        });
      
        return orm;
      };

      So, in short:

      • exportLibrary.db: SQLCipher, but handled indirectly through onelibrary-connect.
      • export.pdb: not SQLCipher; parsed directly.
      • master.db: no evidence in this repo.
      • “device library”: no separate SQLCipher handling visible here beyond exportLibrary.db.

      Important note on search completeness

      The code search results I used may be incomplete because search responses are limited to 10 results. To inspect more matches in GitHub UI, use:

      If you want, I can next trace the likely key source by inspecting the sibling/dependency repo onelibrary-connect and tell you exactly how getEncryptionKey() works.

  • https://github.com/chrisle/onelibrary-connect
    • Read and query rekordbox OneLibrary (exportLibrary.db) SQLCipher databases from Pioneer DJ devices

    • GitHub Copilot (GPT 5.4) Repo Exploration RE: DB Encryption Methods and Keys

      Prompt

      How does this project handle the SQLCipher encryption on the main master.db and device library plus exportLibrary.db ?
      
      Where does it get the key for them from?
      
      Etc
      

      Response

      This project does not fetch SQLCipher keys from the device, OS, user config, or the databases themselves. It uses one hardcoded deobfuscation routine to derive a single built-in SQLCipher key, then applies that key whenever it opens a OneLibrary database.

      Short answer

      • Encryption mode: SQLCipher, with legacy = 4
      • Key source: a hardcoded obfuscated blob in src/encryption.ts
      • How key is derived: base85 decode → XOR with fixed bytes → zlib inflate
      • Where applied: src/connection.ts via SQLCipher pragmas
      • Which DBs this repo actually supports: the code appears to target OneLibrary / exportLibrary.db-style databases, not a separate implementation for master.db

      Relevant code paths

      1) Opening the database

      openOneLibraryDb() is the central DB open path:

      /**
       * OneLibrary Database Connection
       */
      
      import Database from 'better-sqlite3-multiple-ciphers';
      
      import {getEncryptionKey} from './encryption.js';
      
      /**
       * Open a OneLibrary database with SQLCipher decryption
       */
      export function openOneLibraryDb(dbPath: string): Database.Database {
        const key = getEncryptionKey();
      
        const db = new Database(dbPath, {readonly: true});
        db.pragma('cipher = sqlcipher');
        db.pragma('legacy = 4');
        db.pragma(`key = '${key}'`);
      
        return db;
      }

      What this means:

      • it uses better-sqlite3-multiple-ciphers
      • opens the DB read-only
      • explicitly selects SQLCipher
      • sets legacy = 4
      • then sets the SQLCipher key with PRAGMA key

      So the project’s entire encryption handling is basically: derive static key, set SQLCipher pragmas, query normally.


      2) Where the key comes from

      The key derivation is all in src/encryption.ts:

      /**
       * OneLibrary Database Encryption
       *
       * The database is encrypted with SQLCipher 4. The encryption key is derived from
       * a hardcoded obfuscated blob.
       */
      
      import * as zlib from 'zlib';
      
      /**
       * The obfuscated encryption key blob from pyrekordbox
       */
      const BLOB = Buffer.from(
        'PN_1dH8$oLJY)16j_RvM6qphWw`476>;C1cWmI#se(PG`j}~xAjlufj?`#0i{;=glh(SkW)y0>n?YEiD`l%t(',
        'ascii'
      );
      
      /**
       * XOR key used for deobfuscation
       */
      const BLOB_KEY = Buffer.from('657f48f84c437cc1', 'ascii');
      
      /**
       * Base85 (RFC 1924) decode
       */
      function base85Decode(input: Buffer): Buffer {
        const alphabet =
          '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~';
      
        const charToValue = new Map<string, number>();
        for (let i = 0; i < alphabet.length; i++) {
          charToValue.set(alphabet[i], i);
        }
      
        const inputStr = input.toString('ascii');
        const result: number[] = [];
      
        for (let i = 0; i < inputStr.length; i += 5) {
          const chunk = inputStr.slice(i, i + 5);
          let value = 0;
      
          for (const char of chunk) {
            const v = charToValue.get(char);
            if (v === undefined) {
              throw new Error(`Invalid base85 character: ${char}`);
            }
            value = value * 85 + v;
          }
      
          const bytes = [
            (value >> 24) & 0xff,
            (value >> 16) & 0xff,
            (value >> 8) & 0xff,
            value & 0xff,
          ];
      
          const numBytes = chunk.length === 5 ? 4 : chunk.length - 1;
          result.push(...bytes.slice(0, numBytes));
        }
      
        return Buffer.from(result);
      }
      
      /**
       * Deobfuscate the blob to get the encryption key
       */
      function deobfuscate(blob: Buffer): string {
        const decoded = base85Decode(blob);
      
        const xored = Buffer.alloc(decoded.length);
        for (let i = 0; i < decoded.length; i++) {
          xored[i] = decoded[i] ^ BLOB_KEY[i % BLOB_KEY.length];
        }
      
        const decompressed = zlib.inflateSync(xored);
        return decompressed.toString('utf-8');
      }
      
      /**
       * Get the SQLCipher encryption key for OneLibrary databases
       */
      export function getEncryptionKey(): string {
        const key = deobfuscate(BLOB);
        if (!key.startsWith('r8gd')) {
          throw new Error('Invalid encryption key derived');
        }
        return key;
      }

      So the repo is doing this:

      1. start with a hardcoded ASCII blob
      2. decode it as RFC1924 base85
      3. XOR the bytes with a repeating fixed ASCII key: 657f48f84c437cc1
      4. inflate the result with zlib
      5. treat the final UTF-8 text as the SQLCipher key
      6. sanity-check that it starts with r8gd

      Does it get the key from the DB/device?

      No, not in this repo.

      I did not find code that:

      • extracts a key from device metadata
      • negotiates a key with hardware
      • reads a key from property or another table
      • derives per-device keys
      • prompts the user for a password
      • reads env vars or config files for the key

      Instead, the repo comment says the blob is “from pyrekordbox”, so the implementation is essentially reusing known reverse-engineered knowledge.

      What about master.db vs device library vs exportLibrary.db?

      Based on the code present, the project does not have separate encryption logic for different database types.

      What I found:

      • The package description says it reads OneLibrary (exportLibrary.db) SQLCipher databases
      • OneLibraryAdapter always uses openOneLibraryDb(dbPath)
      • openOneLibraryDb() always uses the same static key flow
      • The schema includes fields like masterDbId / masterContentId, but those are just schema fields, not evidence of opening a separate master.db

      For example:

        kuvoDeliveryComment: string | null;
      
        // rekordbox sync
        masterDbId: number | null;
        masterContentId: number | null;
        analysisDataFilePath: number | null;
        analysedBits: number | null;
        contentLink: number | null;

      Those masterDbId references are just columns in the DB schema, not key-management logic.

      So practically:

      • exportLibrary.db: explicitly supported, opened with the built-in SQLCipher key
      • device library DB: if it is the same OneLibrary/SQLCipher format, this code would appear to treat it the same way
      • master.db: I do not see dedicated support or separate handling in this repo

      How broad is support?

      The adapter and comments consistently frame this as OneLibrary / exportLibrary.db support:

      /**
       * OneLibrary Database Adapter
       *
       * Provides an interface for reading the OneLibrary (exportLibrary.db) SQLite database
       * used by modern rekordbox versions and Pioneer DJ devices.
       */

      and:

      {
        "name": "onelibrary-connect",
        "version": "1.0.0",
        "description": "Read and query rekordbox OneLibrary (exportLibrary.db) SQLCipher databases from Pioneer DJ devices",
        ...
      }

      So I would not conclude from this repo alone that it fully implements all variants of:

      • desktop rekordbox master.db
      • device-side library db
      • exported exportLibrary.db

      Instead, I’d conclude it assumes the same known SQLCipher key works for the OneLibrary DBs it targets.

      Important nuance on legacy = 4

      The code uses:

        const db = new Database(dbPath, {readonly: true});
        db.pragma('cipher = sqlcipher');
        db.pragma('legacy = 4');
        db.pragma(`key = '${key}'`);

      This suggests the author expects the DB format to be compatible with SQLCipher’s “legacy 4” setting in better-sqlite3-multiple-ciphers. In practice, that’s a compatibility setting needed to open these DBs correctly with that binding.

      Bottom line

      The project handles encryption in a very simple, centralized way:

      • it assumes the DB is SQLCipher-encrypted
      • it derives one static key from an obfuscated constant
      • it configures the SQLite binding for SQLCipher and legacy = 4
      • it uses that same flow for every DB connection it opens

      It does not appear to:

      • discover keys dynamically
      • use per-device/per-user secrets
      • have separate decryption routines for master.db vs exportLibrary.db

      Best current answer to your specific questions

      “How does this project handle the SQLCipher encryption on the main master.db and device library plus exportLibrary.db?”

      It only visibly implements one decryption path: openOneLibraryDb(). That path applies SQLCipher pragmas and a single derived key. The repository is explicitly built around OneLibrary / exportLibrary.db. I do not see dedicated master.db handling.

      “Where does it get the key for them from?”

      From a hardcoded obfuscated blob in src/encryption.ts, deobfuscated locally in code. Not from the device, not from user input, not from a remote service.

      If you want, I can next:

      1. extract the actual derived key value from the code path, or
      2. compare this repo’s approach to pyrekordbox and explain whether the same key likely applies to master.db too.
  • https://github.com/liamcottle/pioneer-rekordbox-database-encryption
    • PioneerDJ Rekordbox Database Decryption

    • Rekordbox v6 has an encrypted master.db database file. The database file is encrypted with sqlcipher.

See Also

My Other Related Deepdive Gist's and Projects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment