OtterMind/Chat2DB · error · BusinessException

api.decryptPasswordError

api.decryptPasswordError

Error message

api.decryptPasswordError

What it means

BusinessException 'api.decryptPasswordError' from decryptToken when RSA/ECB/PKCS1Padding decryption of an encrypted field (password/host/url/user) fails. This is distinct from 143: here the key decoded fine, but the ciphertext does not decrypt against this key.

Source

Thrown at chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbWorkspaceDataSourceServiceImpl.java:243

        try {
            byte[] keyBytes = Base64.getDecoder().decode(privateKeyString);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            throw new BusinessException("api.privateKeyNotFound");
        }
    }

    private String decryptToken(String encryptedToken, PrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedToken));
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("decrypt token error", e);
            throw new BusinessException("api.decryptPasswordError");
        }
    }

    private String decryptString(String password) {
        if (password == null || password.isEmpty()) {
            return password;
        }
        return AesGcmUtil.configured().decrypt(password);
    }

    private String encryptString(String password) {
        if (password == null || password.isEmpty()) {
            return password;
        }
        return AesGcmUtil.configured().encrypt(password);
    }
}

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. Re-save the datasource credentials so they are re-encrypted with the current organization key.
  2. Ensure the same key pair used at encrypt time is available at decrypt time (check key rotation / environment promotion).
  3. Confirm the stored value is actually the RSA ciphertext, not plain text or AES-encrypted local value.
Defensive patterns

Strategy: fallback

Validate before calling

// ensure field was encrypted with the current key before attempting decrypt
// (no public predicate exists; rely on re-save after key rotation)

Try / catch

try { return decryptToken(token, privateKey); }
catch (BusinessException e) { // api.decryptPasswordError
    // prompt user to re-enter credentials so they are re-encrypted
    throw new CredentialReentryRequiredException();
}

Prevention

When it happens

Trigger: Cipher.doFinal raises (BadPadding/IllegalBlockSize) because the token was encrypted with a different key pair, is not valid Base64, was double-encrypted, or the field is plain text being treated as ciphertext.

Common situations: Datasource was saved under one org key but is being read under another (key rotation mismatch); field was manually edited; migration imported ciphertext without migrating keys; Base64 padding corrupted.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/5cd1d4ce99ffaee6. Report an issue: GitHub.