Openfire: Blowfish PBKDF2 Migration Guide

# Blowfish PBKDF2 Migration Guide

## Introduction

Openfire 5.1.0 introduces PBKDF2-HMAC-SHA512 key derivation for Blowfish encryption, replacing the legacy SHA1 key derivation method. This security enhancement provides significantly improved protection for encrypted properties stored in the Openfire database.

This guide describes how to migrate existing Openfire installations from SHA1 to PBKDF2 key derivation for Blowfish-encrypted properties.

Topics that are covered in this document:

## Security Improvement Overview

The migration from SHA1 to PBKDF2 key derivation improves security in three key ways:

- Slow Key Derivation Function: PBKDF2 uses 100,000 iterations, making brute-force attacks computationally expensive and impractical.
- Random Salt: Each Openfire installation uses a unique random salt (32 bytes), preventing rainbow table attacks and ensuring that identical passwords produce different derived keys across installations.
- Industry Standard Algorithm: PBKDF2-HMAC-SHA512 is a well-vetted algorithm recommended by NIST and other security standards organisations.

What Properties Are Affected: This migration applies to all properties encrypted with Blowfish encryption, including database passwords, LDAP bind passwords, and any custom encrypted properties. Properties encrypted with AES are not affected by this migration.

## Who Needs to Migrate

### New Installations (Openfire 5.1.0+)

Action Required: None. New installations automatically use PBKDF2.

When you complete the setup wizard in Openfire 5.1.0 or later, PBKDF2 key derivation is automatically enabled. You can verify this by accessing the migration page directly at `https://your-server:9090/security-blowfish-migration.jsp`, which will show "Your installation is already using PBKDF2-HMAC-SHA512".

### Existing Installations Using Blowfish Encryption

Action Required: Migration recommended for improved security.

If you upgraded from a previous version of Openfire and use Blowfish encryption (the default), your installation continues to use SHA1 key derivation for backward compatibility. You should migrate to PBKDF2 to benefit from the security improvements.

To check if migration is needed, log into the admin console. If migration is needed, a warning banner will appear on the Server Information page (the homepage) with a link to the migration tool. Alternatively, navigate directly to `https://your-server:9090/security-blowfish-migration.jsp`.

### Existing Installations Using AES Encryption

Action Required: None. This migration does not apply to AES encryption.

If your installation uses AES encryption (configured in `conf/security.xml`), this migration is not applicable. The migration tool will indicate that your server uses AES encryption and no action is required.

## Single-Node Migration Procedure

This procedure applies to standalone Openfire installations (non-clustered). The migration runs while the server continues accepting connections. Users remain connected and can continue messaging throughout the process. The migration is typically fast (under 10 seconds for most installations) and does not interrupt service.

### Prerequisites

Before beginning the migration, ensure you have:

- Administrative access to the Openfire admin console
- Ability to backup the Openfire database
- Access to the server filesystem to backup `conf/security.xml` and `conf/openfire.xml`

### Migration Steps

1. Backup the Database

   Create a complete backup of your Openfire database. The migration is wrapped in a database transaction and will roll back on failure, but having a backup provides an additional safety mechanism.

   Example backup commands:

   - PostgreSQL: `pg_dump openfire > openfire_backup.sql`
   - MySQL: `mysqldump openfire > openfire_backup.sql`
   - MariaDB: `mariadb-dump openfire > openfire_backup.sql`
   - Embedded HSQLDB: `cp -r embedded-db/ embedded-db.backup/`

   Note: Replace "openfire" with your actual database name if different. Check the `<database>` element in `conf/openfire.xml` to confirm your database name.

2. Backup security.xml and openfire.xml

   Create backups of the configuration files:

       cp /opt/openfire/conf/security.xml /opt/openfire/conf/security.xml.backup
       cp /opt/openfire/conf/openfire.xml /opt/openfire/conf/openfire.xml.backup

   (Adjust the path if Openfire is installed in a different location)

3. Access the Migration Page

   Log into the Openfire admin console. If migration is needed, a warning banner will appear on the Server Information page (the homepage) with a link to the migration tool. Click the link, or navigate directly to `https://your-server:9090/security-blowfish-migration.jsp`.

   The page will display the current encryption status, including the key derivation function in use and the number of encrypted properties that will be migrated.

4. Confirm Backups

   Check all three confirmation boxes on the migration page:

   - "I have backed up the Openfire database"
   - "I have backed up the conf/security.xml file"
   - "I have backed up the conf/openfire.xml file"
5. Run the Migration

   Click the "Migrate to PBKDF2" button. You will be prompted to confirm the operation. Click "OK" to proceed.

   The migration process will:

   - Decrypt all encrypted properties using the SHA1-derived key
   - Re-encrypt all properties using the PBKDF2-derived key
   - Update all encrypted values in the database
   - Update `conf/security.xml` to use PBKDF2

   The migration typically completes in under 10 seconds for installations with fewer than 100 encrypted properties.

6. Verify Success

   After successful migration, you will see a success message indicating how many properties were migrated. The migration page will now show "Your installation is using PBKDF2-HMAC-SHA512 key derivation".

   Verify that Openfire continues to function normally:

   - Test database connectivity (indicates database password still decrypts correctly)
   - Test LDAP connections if configured
   - Check that users can authenticate
   - Review `logs/openfire.log` for any errors

   You can also verify the updated `conf/security.xml` contains a `<blowfish>` element (inside the `<encrypt>` section) with the following structure:

       <encrypt>
         ...
         <blowfish>
           <kdf>pbkdf2</kdf>
           <salt>BASE64_ENCODED_SALT</salt>
         </blowfish>
       </encrypt>

### Rollback Procedure (Single-Node)

If you encounter issues after migration and need to rollback:

1. Stop Openfire

       systemctl stop openfire

   Or use the appropriate stop command for your installation method.

2. Restore the Database

   Restore your database backup:

   - PostgreSQL: `psql openfire < openfire_backup.sql`
   - MySQL: `mysql openfire < openfire_backup.sql`
   - MariaDB: `mariadb openfire < openfire_backup.sql`
   - Embedded HSQLDB: `rm -rf embedded-db/ && cp -r embedded-db.backup/ embedded-db/`
3. Restore security.xml and openfire.xml

       cp /opt/openfire/conf/security.xml.backup /opt/openfire/conf/security.xml
       cp /opt/openfire/conf/openfire.xml.backup /opt/openfire/conf/openfire.xml

4. Start Openfire

       systemctl start openfire

5. Verify Rollback

   Verify that Openfire starts successfully and encrypted properties decrypt correctly. The system is now back to using SHA1 key derivation (pre-migration state).

## Clustered Migration Procedure

This procedure applies to Openfire installations with multiple nodes in a cluster. Important: Clustered migration requires a maintenance window as all nodes must be offline during the migration except for the one node performing the migration.

### Why Cluster Migration Requires Downtime

In a clustered environment:

- The database is shared across all nodes (stores encrypted property values)
- The security.xml file is local to each node (stores KDF configuration and salt)

Migration updates both the database (re-encrypted property values) and `security.xml` (KDF setting). If multiple nodes are running with mismatched configurations, nodes using SHA1 will be unable to decrypt properties that were re-encrypted with PBKDF2, causing failures across the cluster.

Critical: You cannot have nodes with different KDF settings accessing the same database simultaneously. This is why all nodes except the migration node must be offline during the migration process.

### Prerequisites

Before beginning the migration, ensure you have:

- Administrative access to all cluster nodes
- Ability to stop and start all cluster nodes
- Ability to backup the shared database
- SSH or filesystem access to all nodes to backup and sync `security.xml` and `openfire.xml`
- A scheduled maintenance window (15-30 minutes recommended)

### Migration Steps

#### Phase 1: Upgrade All Nodes (Optional - Can Use Rolling Upgrade)

If you are upgrading from a version prior to Openfire 5.1.0, you can perform a rolling upgrade first:

1. Upgrade Node 1 to Openfire 5.1.0, restart, verify it joins cluster
2. Upgrade Node 2 to Openfire 5.1.0, restart, verify it joins cluster
3. Upgrade Node 3 to Openfire 5.1.0, restart, verify it joins cluster

At this point, all nodes are running Openfire 5.1.0 but still using SHA1 key derivation (backward compatible). The cluster operates normally. Migration is performed separately during a maintenance window.

#### Phase 2: Plan and Schedule Maintenance Window

4. Schedule a maintenance window (15-30 minutes recommended)
5. Notify users of the planned downtime
6. Prepare backup procedures and rollback plan
7. Choose one node to perform the migration (typically Node 1)

#### Phase 3: Execute Migration (During Maintenance Window)

8. Stop All Cluster Nodes Except One

   Stop all nodes except the one you'll use for migration (e.g., Node 1):

       systemctl stop openfire  # On Node 2
       systemctl stop openfire  # On Node 3
       # etc. for all other nodes

   Verify: Check the admin console on Node 1 shows cluster size = 1, or check logs confirm other nodes have disconnected.

9. Stop the Migration Node

   Stop the remaining node:

       systemctl stop openfire  # On Node 1

   All cluster nodes are now offline.

10. Backup Everything

    Create backups whilst all nodes are offline:

    Backup the shared database:

    - PostgreSQL: `pg_dump openfire > openfire_backup.sql`
    - MySQL: `mysqldump openfire > openfire_backup.sql`
    - MariaDB: `mariadb-dump openfire > openfire_backup.sql`

    Backup `security.xml` and `openfire.xml` on all nodes:

        ssh node1 "cp /opt/openfire/conf/security.xml /opt/openfire/conf/security.xml.backup"
        ssh node1 "cp /opt/openfire/conf/openfire.xml /opt/openfire/conf/openfire.xml.backup"
        ssh node2 "cp /opt/openfire/conf/security.xml /opt/openfire/conf/security.xml.backup"
        ssh node2 "cp /opt/openfire/conf/openfire.xml /opt/openfire/conf/openfire.xml.backup"
        ssh node3 "cp /opt/openfire/conf/security.xml /opt/openfire/conf/security.xml.backup"
        ssh node3 "cp /opt/openfire/conf/openfire.xml /opt/openfire/conf/openfire.xml.backup"

11. Start Migration Node Only

    Start only Node 1 (all other nodes remain stopped):

        systemctl start openfire  # On Node 1 only

    Wait for Node 1 to fully start. Monitor logs or wait until admin console is accessible.

    Verify: Cluster size should be 1 (only this node).

12. Run Migration via Admin Console

    On Node 1, access the admin console. A warning banner will appear on the Server Information page (the homepage) with a link to the migration tool. Click the link, or navigate directly to `https://your-server:9090/security-blowfish-migration.jsp`.

    Check all three confirmation boxes:

    - "I have backed up the Openfire database"
    - "I have backed up the conf/security.xml file"
    - "I have backed up the conf/openfire.xml file"

    Click "Migrate to PBKDF2" and confirm.

    The migration will decrypt all properties (using SHA1), re-encrypt them (using PBKDF2), update the database, and update Node 1's `security.xml`.

    Wait for the success message: "Successfully migrated N properties from SHA1 to PBKDF2".

13. Verify Migration on Node 1

    Check that Node 1's `security.xml` was updated:

        ssh node1 "grep -A2 '<blowfish>' /opt/openfire/conf/security.xml"

    You should see:

        <blowfish>
          <kdf>pbkdf2</kdf>
          <salt>BASE64_ENCODED_SALT</salt>
        </blowfish>

    Important: Note the exact salt value. All nodes must have the same salt.

14. Stop Migration Node

    Stop Node 1 cleanly:

        systemctl stop openfire  # On Node 1

    All nodes are now offline again.

15. Sync security.xml to All Other Nodes

    Copy the updated `security.xml` from Node 1 to all other nodes. You can either copy the entire file or manually edit each node's file.

    Option A - Copy Entire File (Recommended):

        scp node1:/opt/openfire/conf/security.xml node2:/opt/openfire/conf/security.xml
        scp node1:/opt/openfire/conf/security.xml node3:/opt/openfire/conf/security.xml

    Option B - Manual Edit Each Node:

    On each node (Node 2, Node 3, etc.), edit `/opt/openfire/conf/security.xml`:

    - Change `<kdf>sha1</kdf>` to `<kdf>pbkdf2</kdf>`
    - Add the `<salt>` element with the exact Base64 value from Node 1

    Critical: All nodes must have identical KDF and salt values.

16. Sync openfire.xml to Other Nodes (If Applicable)

    If your `openfire.xml` contains encrypted properties (check your `security.xml` for `<property><name>` elements that reference properties stored in openfire.xml), these values were also re-encrypted during migration and must be synced to other nodes.

    Option A - Copy Entire File:

    If all nodes have identical `openfire.xml` configurations (same ports, same network interfaces, same settings):

        scp node1:/opt/openfire/conf/openfire.xml node2:/opt/openfire/conf/openfire.xml
        scp node1:/opt/openfire/conf/openfire.xml node3:/opt/openfire/conf/openfire.xml

    Option B - Manual Sync:

    If nodes have different configurations (different ports, network interfaces, etc.), manually compare the files and copy only the encrypted property values from Node 1 to the other nodes, preserving node-specific settings.

    Note: If your `openfire.xml` does not contain any encrypted properties, you can skip this step.

17. Verify All Nodes Have Matching Configuration

    Compare `security.xml` on all nodes:

        ssh node1 "grep -A2 '<blowfish>' /opt/openfire/conf/security.xml"
        ssh node2 "grep -A2 '<blowfish>' /opt/openfire/conf/security.xml"
        ssh node3 "grep -A2 '<blowfish>' /opt/openfire/conf/security.xml"

    All should show `pbkdf2` and the same salt value.

18. Start All Cluster Nodes

    Start nodes one at a time, verifying each joins the cluster successfully:

        systemctl start openfire  # On Node 1
        # Wait 30-60 seconds, verify Node 1 started successfully

        systemctl start openfire  # On Node 2
        # Wait 30-60 seconds, verify Node 2 joined cluster

        systemctl start openfire  # On Node 3
        # Wait 30-60 seconds, verify Node 3 joined cluster

    Check the admin console or logs to verify cluster size returns to expected count.

19. Verify Cluster Health Post-Migration

    Perform comprehensive verification:

    - Admin console shows all nodes in cluster
    - Test encrypted property access on each node (e.g., database connection works)
    - Create a test encrypted property, verify it replicates across nodes
    - Check `logs/openfire.log` on all nodes for any decryption errors
    - Monitor cluster for 15-30 minutes to ensure stability
20. End of Maintenance Window

    Once cluster health is verified, notify users that the service is back online.

### Critical Errors to Avoid (Clustered Environments)

DO NOT run migration with other nodes still active:

- Problem: Node 1 migrates database to PBKDF2, but Node 2 (still running) tries to decrypt with SHA1.
- Result: Node 2 cannot decrypt properties, cluster breaks, service disruption.

DO NOT start other nodes before syncing security.xml:

- Problem: Node 1 has `kdf=pbkdf2`, but Node 2 still has `kdf=sha1` (not updated).
- Result: Node 2 derives wrong key, cannot decrypt properties, node fails to start or operate correctly.

DO NOT allow salt mismatch between nodes:

- Problem: Node 1 has `salt=abc123...`, but Node 2 has `salt=xyz789...` (different values).
- Result: Different derived keys per node, Node 2 cannot decrypt, cluster inconsistency.

DO NOT forget to sync openfire.xml if it contains encrypted properties:

- Problem: Node 1's `openfire.xml` has re-encrypted values, but Node 2's `openfire.xml` still has SHA1-encrypted values.
- Result: Node 2 cannot decrypt XML-stored properties, configuration errors on startup.

CORRECT PROCEDURE: All nodes stopped → migrate on one node → sync security.xml and openfire.xml (if applicable) to all nodes → start all nodes.

### Rollback Procedure (Clustered)

If you encounter issues after migration and need to rollback:

1. Stop All Cluster Nodes Immediately

       systemctl stop openfire  # On all nodes

2. Restore Shared Database

   Restore the database backup:

   - PostgreSQL: `psql openfire < openfire_backup.sql`
   - MySQL: `mysql openfire < openfire_backup.sql`
   - MariaDB: `mariadb openfire < openfire_backup.sql`
3. Restore security.xml and openfire.xml on All Nodes

       ssh node1 "cp /opt/openfire/conf/security.xml.backup /opt/openfire/conf/security.xml"
       ssh node1 "cp /opt/openfire/conf/openfire.xml.backup /opt/openfire/conf/openfire.xml"
       ssh node2 "cp /opt/openfire/conf/security.xml.backup /opt/openfire/conf/security.xml"
       ssh node2 "cp /opt/openfire/conf/openfire.xml.backup /opt/openfire/conf/openfire.xml"
       ssh node3 "cp /opt/openfire/conf/security.xml.backup /opt/openfire/conf/security.xml"
       ssh node3 "cp /opt/openfire/conf/openfire.xml.backup /opt/openfire/conf/openfire.xml"

4. Verify All Nodes Have KDF=sha1 (Pre-Migration State)

       ssh node1 "grep -A2 '<blowfish>' /opt/openfire/conf/security.xml"
       ssh node2 "grep -A2 '<blowfish>' /opt/openfire/conf/security.xml"
       ssh node3 "grep -A2 '<blowfish>' /opt/openfire/conf/security.xml"

   All should show `sha1` or have no KDF element (defaults to sha1).

5. Start All Nodes

       systemctl start openfire  # On all nodes

6. Verify Cluster Health

   Verify all nodes join the cluster and encrypted properties decrypt correctly. The cluster is now back to using SHA1 key derivation (pre-migration state).

## Troubleshooting

### "Migration failed: Transaction rolled back" Error

Symptom: Migration fails midway through with an error indicating the database transaction was rolled back.

Cause: One or more encrypted properties failed to decrypt or re-encrypt. Possible causes include:

- Corrupted encrypted property value in database
- Database connection issue during migration
- Mismatched encryption key

Solution:

1. Check `logs/openfire.log` for specific property names that failed. The log will indicate which property caused the failure.
2. If the issue is a corrupted property, you may need to delete or manually repair that property before retrying migration.
3. Verify your master encryption key in `security.xml` is correct. If the key was changed, properties encrypted with the old key cannot be decrypted.
4. If the issue persists, restore from backup and report the issue in the Openfire category on the Ignite Realtime community forum with the error logs.

Important: The database transaction rollback means no changes were committed. Your installation remains in the pre-migration state (SHA1) and can continue operating normally. You can investigate the issue and retry migration when resolved.

### Node Fails to Start After Cluster Migration

Symptom: After completing cluster migration, one or more nodes fail to start or fail to decrypt properties.

Cause: The node's `security.xml` was not synced correctly, resulting in KDF or salt mismatch.

Solution:

1. Stop the failing node:

       systemctl stop openfire

2. Copy the updated `security.xml` from the migration node:

       scp working-node:/opt/openfire/conf/security.xml /opt/openfire/conf/security.xml

3. Verify the `<blowfish>` section matches the working node exactly, including KDF and salt values.
4. Restart the node:

       systemctl start openfire

5. Check logs to verify the node starts successfully and joins the cluster.

### Properties Cannot Decrypt After Migration

Symptom: After migration, Openfire fails to decrypt properties. Database connection fails, LDAP connection fails, or other encrypted properties are inaccessible.

Cause: Mismatch between database state and `security.xml`:

- Database contains PBKDF2-encrypted values, but `security.xml` still has `kdf=sha1` (security.xml not updated).
- Database contains SHA1-encrypted values, but `security.xml` has `kdf=pbkdf2` (database not updated, but security.xml was).

Solution:

If database was not updated, but security.xml was changed:

1. Stop Openfire
2. Restore `security.xml` and `openfire.xml` from backups (restores SHA1 setting)
3. Start Openfire - properties should decrypt correctly
4. Retry migration carefully, ensuring migration completes successfully

If database was updated, but security.xml was not:

1. Stop Openfire
2. Manually update `security.xml` to use `<kdf>pbkdf2</kdf>`
3. Ensure the `<salt>` element exists (salt should have been generated during migration)
4. Start Openfire - properties should decrypt correctly

If you cannot resolve the issue:

1. Stop Openfire
2. Restore database, `security.xml`, and `openfire.xml` from backups
3. Start Openfire - system returns to pre-migration state
4. Report the issue in the Openfire category on the Ignite Realtime community forum with error logs before retrying migration

### Getting Help

If you encounter issues not covered in this troubleshooting guide, please seek assistance:

- Community Forum: https://discourse.igniterealtime.org

When seeking help, please include:

- Openfire version number
- How was Openfire installed (RPM, deb, tar.gz, exe, etc.)
- Database type (PostgreSQL, MySQL, etc.)
- Single-node or clustered deployment
- Are you using any custom plugins or authentication methods?
- Relevant excerpts from `logs/openfire.log`
- Contents of the `<blowfish>` section in `security.xml` (safe to share)