使用Java實現(xiàn)Navicat密碼的加密與解密的代碼解析
在日常開發(fā)過程中,我們有時需要處理各種軟件保存的憑據(jù)信息,比如數(shù)據(jù)庫連接密碼等。這篇文章將介紹如何使用Java對Navicat保存的數(shù)據(jù)庫密碼進行加密和解密。
一、背景介紹
Navicat是一款強大的數(shù)據(jù)庫管理工具,支持多種數(shù)據(jù)庫系統(tǒng)。為了保護用戶的數(shù)據(jù)庫憑據(jù),Navicat對用戶輸入的密碼進行了加密處理。本文基于Navicat 12及以后版本使用的AES加密算法,以及Navicat 11及以前版本使用的Blowfish加密算法,展示如何通過Java代碼實現(xiàn)這些密碼的加密和解密。
二、環(huán)境準(zhǔn)備
確保您的開發(fā)環(huán)境中已經(jīng)配置好Java,并且引入了必要的安全庫來支持加密操作。對于本教程,我們將直接使用JDK自帶的javax.crypto包。
三、代碼解析
加密邏輯
- AES加密(適用于Navicat 12及以上版本):采用固定密鑰和初始化向量(IV)。
- Blowfish加密(適用于Navicat 11及以下版本):同樣使用固定的密鑰和IV,但加密過程包括了一步異或操作。
解密邏輯
解密邏輯相對應(yīng)地分為AES解密和Blowfish解密兩種情況,具體實現(xiàn)請參見上述代碼片段中的decryptAES和decryptBlowfish方法。
四、核心代碼展示
package com.aigc.admin.controller;
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;
/**
* @author albert_luo@lizipro.cn
* @version 1.0
* @description: TODO
* @date 04 Apr 2025 00:29
*/
public class NavicatPasswordUtil {
public static void main(String[] args) throws Exception {
// 創(chuàng)建 NavicatPasswordUtil 實例
NavicatPasswordUtil passwordUtil = new NavicatPasswordUtil();
// 待解密的密碼字符串
String encryptedPassword = "30A228E829283FEA8540DA18D2B6A302";
// 解密 Navicat 12 及以后的版本
String decryptedPassword = passwordUtil.decryptPassword(encryptedPassword, NavicatVersion.VERSION_12);
// 正則替換控制符(如響鈴、退格等)
decryptedPassword = decryptedPassword.replaceAll("\\p{Cntrl}", "");
// 輸出解密后的明文 結(jié)果為 shiguang
System.out.println("解密后的密碼: " + decryptedPassword);
}
// AES 加密密鑰
private static final String AES_KEY = "libcckeylibcckey";
// AES 加密向量
private static final String AES_IV = "libcciv libcciv ";
// Blowfish 加密密鑰
private static final String BLOWFISH_KEY = "3DC5CA39";
// Blowfish 加密向量
private static final String BLOWFISH_IV = "d9c7c3c8870d64bd";
/**
* 加密密碼
*
* @param plaintextPassword 明文密碼
* @param navicatVersion 加密版本(NavicatVersion.VERSION_11 或 NavicatVersion.VERSION_12)
* @return 加密后的密文密碼
* @throws Exception 加密過程中可能拋出的異常
*/
public String encryptPassword(String plaintextPassword, NavicatVersion navicatVersion) throws Exception {
switch (navicatVersion) {
case VERSION_11:
return encryptBlowfish(plaintextPassword);
case VERSION_12:
return encryptAES(plaintextPassword);
default:
throw new IllegalArgumentException("不支持的 Navicat 版本");
}
}
/**
* 解密密碼
*
* @param encryptedPassword 密文密碼
* @param navicatVersion 解密版本(NavicatVersion.VERSION_11 或 NavicatVersion.VERSION_12)
* @return 解密后的明文密碼
* @throws Exception 解密過程中可能拋出的異常
*/
public String decryptPassword(String encryptedPassword, NavicatVersion navicatVersion) throws Exception {
switch (navicatVersion) {
case VERSION_11:
return decryptBlowfish(encryptedPassword);
case VERSION_12:
return decryptAES(encryptedPassword);
default:
throw new IllegalArgumentException("不支持的 Navicat 版本");
}
}
/**
* 使用 Blowfish 加密密碼(適用于 Navicat 11 及以前的版本)
*
* @param plaintextPassword 明文密碼
* @return 加密后的密文密碼
* @throws Exception 加密過程中可能拋出的異常
*/
private String encryptBlowfish(String plaintextPassword) throws Exception {
byte[] iv = hexStringToByteArray(BLOWFISH_IV);
byte[] key = hashToBytes(BLOWFISH_KEY);
int round = plaintextPassword.length() / 8;
int leftLength = plaintextPassword.length() % 8;
StringBuilder encryptedResult = new StringBuilder();
byte[] currentVector = iv.clone();
Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
for (int i = 0; i < round; i++) {
byte[] block = xorBytes(plaintextPassword.substring(i * 8, (i + 1) * 8).getBytes(), currentVector);
byte[] encryptedBlock = cipher.doFinal(block);
currentVector = xorBytes(currentVector, encryptedBlock);
encryptedResult.append(bytesToHex(encryptedBlock));
}
if (leftLength > 0) {
currentVector = cipher.doFinal(currentVector);
byte[] block = xorBytes(plaintextPassword.substring(round * 8).getBytes(), currentVector);
encryptedResult.append(bytesToHex(block));
}
return encryptedResult.toString().toUpperCase();
}
/**
* 使用 AES 加密密碼(適用于 Navicat 12 及以后的版本)
*
* @param plaintextPassword 明文密碼
* @return 加密后的密文密碼
* @throws Exception 加密過程中可能拋出的異常
*/
private String encryptAES(String plaintextPassword) throws Exception {
byte[] iv = AES_IV.getBytes();
byte[] key = AES_KEY.getBytes();
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encryptedResult = cipher.doFinal(plaintextPassword.getBytes());
return bytesToHex(encryptedResult).toUpperCase();
}
/**
* 使用 Blowfish 解密密碼(適用于 Navicat 11 及以前的版本)
*
* @param encryptedPassword 密文密碼
* @return 解密后的明文密碼
* @throws Exception 解密過程中可能拋出的異常
*/
private String decryptBlowfish(String encryptedPassword) throws Exception {
byte[] iv = hexStringToByteArray(BLOWFISH_IV);
byte[] key = hashToBytes(BLOWFISH_KEY);
byte[] encryptedBytes = hexStringToByteArray(encryptedPassword.toLowerCase());
int round = encryptedBytes.length / 8;
int leftLength = encryptedBytes.length % 8;
StringBuilder decryptedResult = new StringBuilder();
byte[] currentVector = iv.clone();
Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "Blowfish");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
for (int i = 0; i < round; i++) {
byte[] encryptedBlock = Arrays.copyOfRange(encryptedBytes, i * 8, (i + 1) * 8);
byte[] decryptedBlock = xorBytes(cipher.doFinal(encryptedBlock), currentVector);
currentVector = xorBytes(currentVector, encryptedBlock);
decryptedResult.append(new String(decryptedBlock));
}
if (leftLength > 0) {
currentVector = cipher.doFinal(currentVector);
byte[] block = Arrays.copyOfRange(encryptedBytes, round * 8, round * 8 + leftLength);
decryptedResult.append(new String(xorBytes(block, currentVector), StandardCharsets.UTF_8));
}
return decryptedResult.toString();
}
/**
* 使用 AES 解密密碼(適用于 Navicat 12 及以后的版本)
*
* @param encryptedPassword 密文密碼
* @return 解密后的明文密碼
* @throws Exception 解密過程中可能拋出的異常
*/
private String decryptAES(String encryptedPassword) throws Exception {
byte[] iv = AES_IV.getBytes();
byte[] key = AES_KEY.getBytes();
byte[] encryptedBytes = hexStringToByteArray(encryptedPassword.toLowerCase());
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decryptedResult = cipher.doFinal(encryptedBytes);
return new String(decryptedResult);
}
/**
* 對兩個字節(jié)數(shù)組進行異或操作
*
* @param bytes1 第一個字節(jié)數(shù)組
* @param bytes2 第二個字節(jié)數(shù)組
* @return 異或結(jié)果字節(jié)數(shù)組
*/
private static byte[] xorBytes(byte[] bytes1, byte[] bytes2) {
byte[] result = new byte[bytes1.length];
for (int i = 0; i < bytes1.length; i++) {
result[i] = (byte) (bytes1[i] ^ bytes2[i]);
}
return result;
}
/**
* 將十六進制字符串轉(zhuǎn)換為字節(jié)數(shù)組
*
* @param hexString 十六進制字符串
* @return 字節(jié)數(shù)組
*/
private static byte[] hexStringToByteArray(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
}
return data;
}
/**
* 將字符串哈希為字節(jié)數(shù)組
*
* @param inputString 輸入字符串
* @return 哈希后的字節(jié)數(shù)組
* @throws Exception 哈希過程中可能拋出的異常
*/
private static byte[] hashToBytes(String inputString) throws Exception {
return MessageDigest.getInstance("SHA-1").digest(inputString.getBytes());
}
/**
* 將字節(jié)數(shù)組轉(zhuǎn)換為十六進制字符串
*
* @param byteArray 字節(jié)數(shù)組
* @return 十六進制字符串
*/
private static String bytesToHex(byte[] byteArray) {
StringBuilder result = new StringBuilder();
for (byte b : byteArray) {
result.append(String.format("%02X", b));
}
return result.toString();
}
}
/**
* Navicat 版本枚舉
*/
enum NavicatVersion {
VERSION_11,
VERSION_12
}
五、總結(jié)
通過本文,我們了解了如何利用Java語言實現(xiàn)對Navicat保存的數(shù)據(jù)庫密碼進行加密和解密。這不僅有助于加深對加密技術(shù)的理解,同時也為實際項目中處理類似需求提供了參考方案。需要注意的是,在真實的應(yīng)用場景中,應(yīng)當(dāng)遵循最佳的安全實踐,如定期更換密鑰、避免硬編碼敏感信息等。
希望這篇博客能幫助讀者更好地理解和應(yīng)用Java中的加密技術(shù)。如果想要深入了解,建議嘗試修改并運行上述代碼,觀察不同參數(shù)設(shè)置下的輸出結(jié)果。
到此這篇關(guān)于使用Java實現(xiàn)Navicat密碼的加密與解密的代碼解析的文章就介紹到這了,更多相關(guān)java Navicat密碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JAVALambda表達(dá)式與函數(shù)式接口詳解
大家好,本篇文章主要講的是JAVALambda表達(dá)式與函數(shù)式接口詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下2022-02-02
使用BufferedReader讀取TXT文件中數(shù)值,并輸出最大值
這篇文章主要介紹了使用BufferedReader讀取TXT文件中數(shù)值,并輸出最大值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Java14對于NullPointerException的新處理方式示例解析
這篇文章主要為大家介紹了Java14對于NullPointerException的新處理方式示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
java如何獲取request中json數(shù)據(jù)
這篇文章主要給大家介紹了關(guān)于java如何獲取request中json數(shù)據(jù)的相關(guān)資料,文中通過代碼示例以及圖文將獲取的方法介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用java具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08
springboot使用Mybatis-plus分頁插件的案例詳解
這篇文章主要介紹了springboot使用Mybatis-plus分頁插件的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-05-05

