How the Chat2DB Navicat/DBWeaver Import Feature Decrypts Connection Passwords

The Navicat/DBWeaver import feature decrypts connection passwords by selecting a version-specific cipher implementation—either Blowfish for Navicat 11 or AES for Navicat 12+—via the CipherFactory, then applying the algorithm to hex-encoded ciphertext to recover the plaintext credentials.

When migrating database connections from Navicat or DBWeaver into Chat2DB, the import process must handle encrypted passwords stored in .ncx export files. The Chat2DB source code implements dedicated cipher classes in the chat2db-community-domain-core module that reverse-engineer Navicat's proprietary encryption schemes. This allows the TaskNcxImportServiceImpl to transparently recover credentials during the import workflow.

Cipher Selection Via the Factory Pattern

The import service delegates password decryption to the CipherFactory, which maintains a registry mapping version identifiers to concrete CommonCipher implementations. When processing an .ncx file, the service extracts the version enum and requests the appropriate cipher instance.

// TaskNcxImportServiceImpl delegates to the factory
CommonCipher cipher = CipherFactory.get(VersionEnum.native11.name());
// or for modern exports
CommonCipher cipher = CipherFactory.get(VersionEnum.navicat12more.name());

VersionEnum Strategy

The factory recognizes two primary export formats:

  • VersionEnum.native11 — Maps to Navicat11Cipher for Blowfish-based encryption used in older Navicat releases.
  • VersionEnum.navicat12more — Maps to Navicat12Cipher for AES-based encryption introduced in Navicat 12 and later.

This enum-driven approach ensures backward compatibility while supporting modern encryption standards.

For exports generated by Navicat 11, the Navicat11Cipher class (located at chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ncx/cipher/Navicat11Cipher.java) handles decryption using a custom Blowfish implementation. Unlike standard Blowfish/ECB, this cipher employs a variant of CBC mode with a statically derived key and a dynamically generated initialization vector.

Key Derivation and IV Generation

The cipher derives its secret key from the hardcoded constant DefaultUserKey = "3DC5CA39". It hashes this string using SHA-1 to produce the Blowfish key material. The initialization vector is generated by encrypting a constant block of 0xFF bytes with the Blowfish encryptor, creating the starting IV for the chaining process.

The Custom CBC Decryption Routine

The decryptString method processes hex-encoded ciphertext through the following steps:

  1. Convert the hex string to a byte array.
  2. Decrypt the data in 8-byte blocks using Blowfish.
  3. XOR each decrypted block with the evolving IV (a variant of CBC mode) before returning the result as a UTF-8 string.
// Simplified representation of Navicat11Cipher logic
public String decryptString(String ciphertext) {
    byte[] encrypted = parseHexBinary(ciphertext);
    // Initialize Blowfish with SHA-1 hashed DefaultUserKey
    Cipher blowfish = initBlowfishCipher();
    byte[] iv = generateIV(blowfish); // Encrypt 0xFF block
    
    byte[] decrypted = new byte[encrypted.length];
    byte[] previousBlock = iv;
    
    for (int i = 0; i < encrypted.length; i += 8) {
        byte[] block = Arrays.copyOfRange(encrypted, i, i + 8);
        byte[] decryptedBlock = blowfish.update(block);
        // XOR with previous ciphertext block (CBC mode)
        for (int j = 0; j < 8; j++) {
            decrypted[i + j] = (byte) (decryptedBlock[j] ^ previousBlock[j]);
        }
        previousBlock = block;
    }
    return new String(decrypted, StandardCharsets.UTF_8).trim();
}

For Navicat 12, 15, and later versions, Navicat12Cipher (located at chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ncx/cipher/Navicat12Cipher.java) utilizes standard AES-128 in CBC mode with PKCS5 padding. This implementation uses fixed, hardcoded key and IV values embedded in the Navicat binary.

AES Parameters

The decryption relies on these static parameters:

  • Key: "libcckeylibcckey" (16 bytes) wrapped in a SecretKeySpec.
  • IV: "libcciv libcciv " (16 bytes) wrapped in an IvParameterSpec.
  • Algorithm: AES/CBC/PKCS5Padding.
// Navicat12Cipher implementation
private static final String AES_KEY = "libcckeylibcckey";
private static final String AES_IV = "libcciv libcciv ";

public String decryptString(String ciphertext) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    SecretKeySpec keySpec = new SecretKeySpec(AES_KEY.getBytes(), "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(AES_IV.getBytes());
    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
    
    byte[] decoded = parseHexBinary(ciphertext);
    byte[] decrypted = cipher.doFinal(decoded);
    return new String(decrypted, StandardCharsets.UTF_8);
}

Practical Decryption Workflow

Putting the components together, the complete workflow for decrypting a connection password from an .ncx file looks like this:

import ai.chat2db.community.domain.core.impl.ncx.CipherFactory;
import ai.chat2db.community.domain.core.impl.ncx.cipher.CommonCipher;
import ai.chat2db.community.domain.core.impl.ncx.enums.VersionEnum;

public class PasswordDecryptor {
    public String decryptPassword(String encryptedHex, String navicatVersion) {
        // Select cipher based on export version
        CommonCipher cipher = CipherFactory.get(
            navicatVersion.equals("11") 
                ? VersionEnum.native11.name() 
                : VersionEnum.navicat12more.name()
        );
        
        // Decrypt the hex-encoded password
        return cipher.decryptString(encryptedHex);
    }
}

The CipherFactory.get() method returns the singleton instance of the requested cipher, which is then used to transform the stored hex string back into the plaintext password required for establishing database connections.

Summary

  • The CipherFactory registers Navicat11Cipher and Navicat12Cipher, selecting the appropriate implementation based on VersionEnum.native11 or VersionEnum.navicat12more.
  • Navicat11Cipher implements a custom Blowfish decryption routine with a SHA-1 derived key from the static string "3DC5CA39" and a dynamically generated IV.
  • Navicat12Cipher utilizes standard AES/CBC/PKCS5Padding with the fixed key "libcckeylibcckey" and IV "libcciv libcciv ".
  • TaskNcxImportServiceImpl orchestrates the import process by extracting version metadata, obtaining the correct cipher, and calling decryptString() on hex-encoded passwords from .ncx files.

Frequently Asked Questions

What encryption algorithm does Navicat 11 use for passwords?

Navicat 11 uses a custom Blowfish implementation with a static key derived from SHA-1 hashing of "3DC5CA39". The algorithm employs a CBC-like mode where the IV is generated by encrypting a block of 0xFF bytes, and decryption involves XORing blocks with the previous ciphertext block.

How does Chat2DB determine which cipher to use during import?

Chat2DB examines the version metadata stored within the .ncx export file. The TaskNcxImportServiceImpl maps this version to VersionEnum.native11 (for Blowfish) or VersionEnum.navicat12more (for AES), then requests the corresponding cipher from the CipherFactory using the enum name as the lookup key.

Is the Navicat 12 encryption key secure?

No. The AES key "libcckeylibcckey" and IV "libcciv libcciv " are hardcoded constants embedded in the Navicat application binary. This is obfuscation, not secure encryption, as anyone with access to the Navicat binary (or this open-source implementation) can decrypt the passwords. Chat2DB uses these known keys to provide import compatibility.

Can this decryption handle DBWeaver exports as well?

Yes. DBWeaver exports that utilize the .ncx format (the same as Navicat) are processed through the same TaskNcxImportServiceImpl pathway. The service treats them as Navicat-compatible exports and applies the same version detection and cipher selection logic to decrypt connection passwords.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →