适用版本:
SecureCRT 7.3.3 之后的版本 - Password V2 算法
参考文章:
全部代码:
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Random;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class SecureCRTPwdDecrypt {
// 初始向量
private static final byte[] IV = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 如果未设置配置密码,则密钥为SHA256的空字符串摘要
private static final byte[] KEY = AES256.autoKey(AES256.getSHA256Str(""));
// 如果设置配置密码,则密钥为
// private static byte[] passphrase = {
// (byte) 0xe3, (byte) 0xb0, (byte) 0xc4, 0x42, (byte) 0x98, (byte) 0xfc, 0x1c, 0x14,
// (byte) 0x9a, (byte) 0xfb, (byte) 0xf4, (byte) 0xc8, (byte) 0x99, 0x6f, (byte) 0xb9, 0x24,
// 0x27, (byte) 0xae, 0x41, (byte) 0xe4, 0x64, (byte) 0x9b, (byte) 0x93, 0x4c,
// (byte) 0xa4, (byte) 0x95, (byte) 0x99, 0x1b, 0x78, 0x52, (byte) 0xb8, 0x55
// };
public static void main(String[] args) throws Exception {
String plainText = "1234567";
String encHexStr = passwordV2EnDecrytion(plainText);
System.out.println(encHexStr.toLowerCase());
String passwd = passwordV2Decrytion(encHexStr);
System.out.println(passwd);
}
private static String passwordV2Decrytion(String encDataStr) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
// 1. 16进制字符串转成 byte[]
byte[] encData = AES256.hexStringToBytes(encDataStr);
// 2. 解密
byte[] decData = AES256.AES_cbc_decrypt(encData, KEY, IV);
// 3. 取出前四个字节,转换成 int 类型,获取实际字节长度
int length = AES256.bytesToInt(decData);
// 4. 取出密码
byte[] passwdData = new byte[length];
System.arraycopy(decData, 4, passwdData, 0, length);
// 5. 转成字符串
String passwd = new String(passwdData, "UTF-8");
return passwd;
}
private static String passwordV2EnDecrytion(String plainText) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
// 1. 转成字节数组
byte[] plainBytes = plainText.getBytes("UTF-8");
// 2. 获取字节数组长度
int length = plainBytes.length;
byte[] lengthBytes = AES256.intToBytes(length);
// 3. 把长度放到字节数组前
byte[] lengthPasswdBytes = new byte[length + 4];
System.arraycopy(lengthBytes, 0, lengthPasswdBytes, 0, 4);
System.arraycopy(plainBytes, 0, lengthPasswdBytes, 4, plainBytes.length);
// 4. 后面加上 原始明文的.digest()
byte[] plainTextDigest = AES256.getSHA256(plainBytes);
byte[] lengthPasswdDigestBytes = new byte[lengthPasswdBytes.length + plainTextDigest.length];
System.arraycopy(lengthPasswdBytes, 0, lengthPasswdDigestBytes, 0, lengthPasswdBytes.length);
System.arraycopy(plainTextDigest, 0, lengthPasswdDigestBytes, lengthPasswdBytes.length, plainTextDigest.length);
// 5. 后面加上 随机的,并且与前面的数组组成长度为16的倍数的字节数组
byte[] randomBytes = buildRandomBytes(16 - lengthPasswdDigestBytes.length % 16);
byte[] allBytes = new byte[lengthPasswdDigestBytes.length + randomBytes.length];
System.arraycopy(lengthPasswdDigestBytes, 0, allBytes, 0, lengthPasswdDigestBytes.length);
System.arraycopy(randomBytes, 0, allBytes, lengthPasswdDigestBytes.length, randomBytes.length);
// 6. 加密
byte[] encData = AES256.AES_cbc_encrypt(allBytes, KEY, IV);
// 7. 转成16进制字符串
String encHexStr = AES256.bytesToHex(encData);
return encHexStr;
}
private static byte[] buildRandomBytes(int length) {
Random rd = new Random();
byte[] arr = new byte[length];
rd.nextBytes(arr);
return arr;
}
}
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AES256 {
static {
/*AES 加密默认128位的key,这里改成256位的(类在下面粘出来了)*/
UnlimitedKeyStrengthJurisdictionPolicy.ensure();
}
/*加密算法*/
private static final String ALGORITHM = "AES/CBC/NoPadding";
/**
*
* @param srcData 要加密的数组(String 需要base64 编码)
* @param key 公钥,32位byte数组
* @param iv 私钥,16位byte数组
* @return 加密后的byte数组
* @throws Exception 找不到加密算法等
*/
public static byte[] AES_cbc_encrypt(byte[] srcData, byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher.getMaxAllowedKeyLength(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
return cipher.doFinal(srcData);
}
/**
*
* @param encData 要解密的数组
* @param key 公钥
* @param iv 私钥
* @return 解密后的byte数组
* @throws Exception 找不到解密算法等
*/
public static byte[] AES_cbc_decrypt(byte[] encData, byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher.getMaxAllowedKeyLength(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
return cipher.doFinal(encData);
}
//长度不够处理
public static byte[] autoKey(byte[] key){
byte[] bytes = new byte[32];
for (int i =0;i<32;i++){
bytes[i]=0;
}
if (key.length>=32){
System.arraycopy(key,0,bytes,0,32);
}else {
System.arraycopy(key,0,bytes,0,key.length);
}
return bytes;
}
//256加密
public static byte[] getSHA256Str(String str){
byte[] encdeStr = null;
try {
encdeStr = getSHA256(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encdeStr;
}
//256加密
public static byte[] getSHA256(byte[] bytes){
MessageDigest messageDigest;
byte[] encdeStr = null;
try {
messageDigest = MessageDigest.getInstance("SHA-256");
encdeStr = messageDigest.digest(bytes);
//encdeStr = Hex.encodeHexString(hash);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encdeStr;
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
public static byte[] intToBytes(int a){
byte[] ans=new byte[4];
for(int i=0;i<4;i++)
ans[i]=(byte)(a>>(i*8));
return ans;
}
public static int bytesToInt(byte[] a){
int ans=0;
for(int i=0;i<4;i++){
ans<<=8;
ans|=(a[3-i]&0xff);
}
return ans;
}
public static String bytesToHex(byte[] bytes) {
StringBuffer sb = new StringBuffer();
if (bytes != null && bytes.length > 0) {
for (int i = 0; i < bytes.length; i++) {
String hex = byteToHex(bytes[i]);
sb.append(hex);
}
}
return sb.toString();
}
public static String byteToHex(byte b) {
String hexString = Integer.toHexString(b & 0xFF);
// 由于十六进制是由0~9、A~F来表示1~16,所以如果Byte转换成Hex后如果是<16,就会是一个字符(比如A=10),通常是使用两个字符来表示16进制位的,
// 假如一个字符的话,遇到字符串11,这到底是1个字节,还是1和1两个字节,容易混淆,如果是补0,那么1和1补充后就是0101,11就表示纯粹的11
if (hexString.length() < 2) {
hexString = new StringBuilder(String.valueOf(0)).append(hexString).toString();
}
return hexString.toUpperCase();
}
}
import javax.crypto.Cipher;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Map;
// https://stackoverflow.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an
public class UnlimitedKeyStrengthJurisdictionPolicy {
private static boolean isRestrictedCryptography() throws NoSuchAlgorithmException {
return Cipher.getMaxAllowedKeyLength("AES/ECB/NoPadding") <= 128;
}
private static void removeCryptographyRestrictions() {
try {
if (!isRestrictedCryptography()) {
// System.out.println("Cryptography restrictions removal not needed");
return;
}
/*
* Do the following, but with reflection to bypass access checks:
*
* JceSecurity.isRestricted = false;
* JceSecurity.defaultPolicy.perms.clear();
* JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
*/
Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
isRestrictedField.set(null, false);
Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map<?, ?>) perms.get(defaultPolicy)).clear();
Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission) instance.get(null));
System.out.println("Successfully removed cryptography restrictions");
} catch (Exception e) {
System.out.println("Failed to remove cryptography restrictions" + e);
}
}
static {
removeCryptographyRestrictions();
}
public static void ensure() {
// just force loading of this class
}
}