企业级开发中会有很多数据库链接信息,如果有遗漏可能就会导致忘记了数据库密码,那么使用 navicat 存储过数据库信息就可以查询到数据库密码,操作方式如下:参考博客 , 参考博文导出数据库链接信息,博文写的 php 代码已经无法执行,借助 grok 整了一个 Java 版本的。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
public class NavicatPassword {
private final int version;
private final byte[] aesKey = "libcckeylibcckey".getBytes(StandardCharsets.UTF_8);
private final byte[] aesIv = "libcciv libcciv".getBytes(StandardCharsets.UTF_8);
private final byte[] blowKey;
private final byte[] blowIv;
public NavicatPassword(int version) throws Exception {
this.version = version;
String blowString = "3DC5CA39";
this.blowKey = sha1(blowString);
this.blowIv = hexToBytes("d9c7c3c8870d64bd");
}
public String decrypt(String hexCipher) throws Exception {
return switch (version) {
case 11 -> decryptEleven(hexCipher);
case 12 -> decryptTwelve(hexCipher);
default -> throw new IllegalArgumentException("Unsupported version:" + version);
};
}
private String decryptTwelve(String hexCipher) throws Exception {
byte[] encrypted = hexToBytes(hexCipher);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(aesIv);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted, StandardCharsets.UTF_8);
}
private String decryptEleven(String hexCipher) throws Exception {
byte[] data = hexToBytes(hexCipher);
byte[] result = new byte[0];
byte[] currentVector = Arrays.copyOf(blowIv, blowIv.length);
int rounds = data.length / 8;
int left = data.length % 8;
for (int i = 0; i < rounds; i++) {
byte[] block = Arrays.copyOfRange(data, i * 8, i * 8 + 8);
byte[] decrypted = decryptBlowfish(block);
byte[] xored = xorBytes(decrypted, currentVector);
currentVector = xorBytes(currentVector, block);
result = concat(result, xored);
}
if (left > 0) {
byte[] padded = encryptBlowfish(currentVector);
byte[] last = xorBytes(Arrays.copyOfRange(data, rounds * 8, data.length),
Arrays.copyOf(padded, left));
result = concat(result, last);
}
return new String(result, StandardCharsets.UTF_8);
}
private byte[] encryptBlowfish(byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(blowKey, "Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
return cipher.doFinal(input);
}
private byte[] decryptBlowfish(byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(blowKey, "Blowfish");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
return cipher.doFinal(input);
}
// Utility methods
private byte[] xorBytes(byte[] a, byte[] b) {
byte[] result = new byte[a.length];
for (int i = 0; i < result.length; i++) {
result[i] = (byte) (a[i] ^ b[i]);
}
return result;
}
private byte[] sha1(String input) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-1");
return md.digest(input.getBytes(StandardCharsets.UTF_8));
}
private static byte[] hexToBytes(String hex) {
int len = hex.length();
byte[] result = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
result[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+ Character.digit(hex.charAt(i + 1), 16));
}
return result;
}
private static byte[] concat(byte[] a, byte[] b) {
byte[] result = Arrays.copyOf(a, a.length + b.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
public static void main(String[] args) throws Exception {
NavicatPassword np = new NavicatPassword(12);
String encrypted = "connections.ncx 文件里面的 password";
String decrypted = np.decrypt(encrypted);
System.out.println("Decrypted:" + decrypted);
}
}
代码复制到 idea 执行即可