JAVA 3DES加密 ECB模式 ZeroPadding填充「终于解决」

JAVA 3DES加密 ECB模式 ZeroPadding填充「终于解决」3DESECBZeroPadding前言解决相关类前言因金融机构支付相关的接口需要对敏感数据加密,采用3DES加密。刚开始以为这个加密网上找一大堆,没想到一无所获。解决由于不熟悉这个加密,对数据的位数不足填充不是特别了解,功力不够。最后终于在github找到了。github地址:https://github.com/quanqiang-li/knowledge相关类加密类Cip…

大家好,欢迎来到IT知识分享网。

3DES ECB ZeroPadding

前言

因金融机构支付相关的接口需要对敏感数据加密,采用3DES加密。刚开始以为这个加密网上找一大堆,没想到一无所获。

解决

由于不熟悉这个加密,对数据的位数不足填充不是特别了解,功力不够。最后终于在github找到了。
github地址:https://github.com/quanqiang-li/knowledge

相关类

加密类 CipherUtil.

// 

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/** * 公钥加密,私钥解密 * <p> * 证书算法: x509Certificate.getSigAlgName() 用来加签/验签 <br> * keytool -genkeypair -sigalg SHA1withRSA <br> * 密钥算法:key.getAlgorithm() 用来加密/解密 创建密钥对的时候指定的 <br> * keytool -genkeypair -keyalg RSA<br> * * @author aisino 参考顺序 * MessageDigestUtil--》KeyToolUtil--》SignatureUtil--》CipherUtil */
public class CipherUtil { 
   

	public static final String CHARSET_UTF8 = "UTF-8";
	public static final String Algorithm_AES = "AES";
	public static final String Algorithm_DES = "DES";
	public static final String Algorithm_DESede = "DESede";// 也叫3DES/模式/填充,默认等同于DESede/ECB/PKCS5Padding
	public static final String Algorithm_RSA = "RSA";
	public static final String Algorithm_PBEWithMD5AndDES = "PBEWithMD5AndDES";

	public static void main(String[] args) { 
   
// String msg = "你好hello12a c";
// Certificate certificate = KeyToolUtil.getCert("carl.crt");
// String encryptMsg = encryptMsg(msg, certificate);
// System.out.println(certificate.getPublicKey().getAlgorithm() + "加密串:" + encryptMsg);
// PrivateKey privateKey = KeyToolUtil.getPrivateKeyFromKeyStore("JKS", "carl.keystore", "qq2476056494", "carl",
// "qq2476056494");
// String decryptMsg = decryptMsg(encryptMsg, privateKey);
// System.out.println(privateKey.getAlgorithm() + "解密后:" + decryptMsg);
// System.out.println("==============以下是采用密钥串来加解密的===================");
// // 3des的密钥串只能是24个字节的长度,采用utf编码则24个字母数字,或者8个中文
// String key = "abcdefghijklmnopqrstuvwx";
// String encryptMsg2 = encryptMsg(key, Algorithm_DESede, msg);
// System.out.println("\n" + Algorithm_DESede + "加密串:" + encryptMsg2);
// String decryptMsg2 = decryptMsg(key, Algorithm_DESede, encryptMsg2);
// System.out.println("\n" + Algorithm_DESede + "解密后:" + decryptMsg2);
		System.out.println("==============以下是3des/ecb/zeroPadding加解密的===================");
		String deskey = "111111111111111111111111";
		String encryptWithDESCEBZeroPading = encryptWithDESCEBZeroPading(deskey, "511113197310071016");
		System.out.println("\n加密串" + encryptWithDESCEBZeroPading);
		String decryptWithDESCEBZeroPading = decryptWithDESCEBZeroPading(deskey, encryptWithDESCEBZeroPading);
		System.out.println("\n解密串" + decryptWithDESCEBZeroPading);
	}

	/** * 加密数据,证书里公钥的算法 * * @param msg * 数据 * @param certificate * 证书(公钥) * @return base64编码处理的字符串 */
	public static String encryptMsg(String msg, Certificate certificate) { 
   
		try { 
   
			// 使用证书公钥的算法,生成密钥对的时候指定的算法
			Cipher instance = Cipher.getInstance(certificate.getPublicKey().getAlgorithm());
			// ENCRYPT_MODE 加密模式
			instance.init(Cipher.ENCRYPT_MODE, certificate);
			instance.update(msg.getBytes(CHARSET_UTF8));
			byte[] doFinal = instance.doFinal();
			return Base64.getEncoder().encodeToString(doFinal);
		} catch (NoSuchAlgorithmException e) { 
   
			e.printStackTrace();
		} catch (NoSuchPaddingException e) { 
   
			e.printStackTrace();
		} catch (InvalidKeyException e) { 
   
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) { 
   
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) { 
   
			e.printStackTrace();
		} catch (BadPaddingException e) { 
   
			e.printStackTrace();
		}
		return null;
	}

	/** * 解密数据,私钥的算法 * * @param encryptMsg * 加密后字符串,且base64编码处理过 * @param privateKey * 私钥 * @return 解密后的数据 */
	public static String decryptMsg(String encryptMsg, PrivateKey privateKey) { 
   
		try { 
   
			// 使用私钥的算法,生成密钥对的时候指定的算法
			Cipher instance = Cipher.getInstance(privateKey.getAlgorithm());
			// DECRYPT_MODE 解密模式
			instance.init(Cipher.DECRYPT_MODE, privateKey);
			instance.update(Base64.getDecoder().decode(encryptMsg));
			byte[] doFinal = instance.doFinal();
			return new String(doFinal, CHARSET_UTF8);
		} catch (InvalidKeyException e) { 
   
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) { 
   
			e.printStackTrace();
		} catch (NoSuchPaddingException e) { 
   
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) { 
   
			e.printStackTrace();
		} catch (BadPaddingException e) { 
   
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) { 
   
			e.printStackTrace();
		}
		return null;
	}

	/** * 没有证书的情况下,采用指定密钥串加密 * * @param key * 密钥 * @param Algorithm * 加密算法 * @param msg * 消息 * @return Base64编码后的字符串 */
	public static String encryptMsg(String key, String Algorithm, String msg) { 
   
		try { 
   
			// 生成密钥
			byte[] bytes = key.getBytes(CHARSET_UTF8);
			System.out.println("密钥字节长度:" + bytes.length);
			SecretKey deskey = new SecretKeySpec(bytes, Algorithm);
			// 加密工具
			Cipher c1 = Cipher.getInstance(Algorithm);
			// 加密
			c1.init(Cipher.ENCRYPT_MODE, deskey);
			byte[] msgBytes = msg.getBytes(CHARSET_UTF8);
			System.out.println("原数据字节如下:");
			for (int i = 0; i < msgBytes.length; i++) { 
   
				System.out.print(msgBytes[i] + "\t");
			}
			// FIXME 此处不能使用update
			byte[] doFinal = c1.doFinal(msgBytes);
			System.out.println("\n加密后的字节如下:");
			for (int i = 0; i < doFinal.length; i++) { 
   
				System.out.print(doFinal[i] + "\t");
			}
			return Base64.getEncoder().encodeToString(doFinal);
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
		return null;
	}

	/** * 3des ecb 0填充,利用NoPading,自行补0 * * @param key * 密钥串,必须为24长度字符串 * @param msg * 消息 * @return Base64编码后的字符串 */
	public static String encryptWithDESCEBZeroPading(String key, String msg) { 
   
		try { 
   
			// 生成密钥
			byte[] bytes = key.getBytes(CHARSET_UTF8);
			System.out.println("密钥字节长度:" + bytes.length);
			SecretKey deskey = new SecretKeySpec(bytes, "DESede");
			// 加密工具
			Cipher c1 = Cipher.getInstance("DESede/ECB/NoPadding");
			// 加密
			c1.init(Cipher.ENCRYPT_MODE, deskey);
			byte[] msgBytes = msg.getBytes(CHARSET_UTF8);
			System.out.println("原数据字节如下:");
			for (int i = 0; i < msgBytes.length; i++) { 
   
				System.out.print(msgBytes[i] + "\t");
			}
			// FIXME 自行补位,达到8字节的倍数
			int remainder = msgBytes.length % 8;
			if (0 != remainder) { 
   
				int oldLength = msgBytes.length;
				// 1.扩展自身长度
				msgBytes = Arrays.copyOf(msgBytes, msgBytes.length + 8 - remainder);
				// 2.填充扩展内容为0
				Arrays.fill(msgBytes, oldLength, msgBytes.length, (byte) 0);

			}
			// FIXME 此处不能使用update,自行补位,
			byte[] doFinal = c1.doFinal(msgBytes);
			System.out.println("\n加密后的字节如下:");
			for (int i = 0; i < doFinal.length; i++) { 
   
				System.out.print(doFinal[i] + "\t");
			}
			return Base64.getEncoder().encodeToString(doFinal);
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
		return null;
	}

	/** * 没有证书的情况下,使用密钥串解密 * * @param key * 密钥串 * @param Algorithm * 算法 * @param encryptMsg * 已加密的字节经base64编码后的字符串 * @return 原始数据,utf-8编码 */
	public static String decryptMsg(String key, String Algorithm, String encryptMsg) { 
   
		try { 
   
			// 生成密钥
			byte[] bytes = key.getBytes(CHARSET_UTF8);
			System.out.println("密钥字节长度:" + bytes.length);
			SecretKey deskey = new SecretKeySpec(bytes, Algorithm);
			// 初始工具
			Cipher instance = Cipher.getInstance(Algorithm);
			// DECRYPT_MODE 解密模式
			instance.init(Cipher.DECRYPT_MODE, deskey);
			byte[] encryptMsgBytes = Base64.getDecoder().decode(encryptMsg);
			System.out.println("待解密的字节如下:");
			for (int i = 0; i < encryptMsgBytes.length; i++) { 
   
				System.out.print(encryptMsgBytes[i] + "\t");
			}
			// FIXME 此处不能使用update
			byte[] doFinal = instance.doFinal(encryptMsgBytes);
			System.out.println("\n解密后的字节为如下:");
			for (int i = 0; i < doFinal.length; i++) { 
   
				System.out.print(doFinal[i] + "\t");
			}
			return new String(doFinal, CHARSET_UTF8);
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
		return null;
	}

	/** * 3des ecb 0填充,解密;利用NoPading,自行去除填充的0 * * @param key * 密钥字符串,必须是24长度 * @param encryptMsg * base64的密文 * @return */
	public static String decryptWithDESCEBZeroPading(String key, String encryptMsg) { 
   
		try { 
   
			// 生成密钥
			byte[] bytes = key.getBytes(CHARSET_UTF8);
			System.out.println("密钥字节长度:" + bytes.length);
			SecretKey deskey = new SecretKeySpec(bytes, "DESede");
			// 初始工具
			Cipher instance = Cipher.getInstance("DESede/ECB/NoPadding");
			// DECRYPT_MODE 解密模式
			instance.init(Cipher.DECRYPT_MODE, deskey);
			byte[] encryptMsgBytes = Base64.getDecoder().decode(encryptMsg);
			System.out.println("待解密的字节如下:");
			for (int i = 0; i < encryptMsgBytes.length; i++) { 
   
				System.out.print(encryptMsgBytes[i] + "\t");
			}
			// FIXME 此处不能使用update
			byte[] doFinal = instance.doFinal(encryptMsgBytes);
			// 去除填充的0,倒数第一个不为0的位置,copy到另一个数组
			int zeroIndex = doFinal.length;
			for (int i = doFinal.length - 1; i > 0; i--) { 
   
				if (doFinal[i] == (byte) 0) { 
   
					zeroIndex = i;
				} else { 
   
					break;
				}
			}
			doFinal = Arrays.copyOf(doFinal, zeroIndex);
			System.out.println("\n解密后的字节为如下:");
			for (int i = 0; i < doFinal.length; i++) { 
   
				System.out.print(doFinal[i] + "\t");
			}
			return new String(doFinal, CHARSET_UTF8);
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
		return null;
	}

}

依赖的工具类 KeyToolUtil


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import sun.security.tools.keytool.Main;

/** * 密钥和证书管理工具 * * @author aisino * 参考顺序 * MessageDigestUtil--》KeyToolUtil--》SignatureUtil--》CipherUtil */
public class KeyToolUtil { 
   

	public static void main(String[] args) throws Exception { 
   
		//命令:keytool -list -keystore test.keystore
		//这里省略开头的keytool,这里Main本身就是keytool工具,使用空格拆分的命令
		
		//printAllCommand();
		//printCommandHelp("export");
		//生成密钥对,会提示输入密码,机构;域名liquanqiang.aisino.com来倒着填,按地址倒着填,keyalg 加解密用,sigalg 加签验签用,这两个算法要属于一个体系内
		//execCommand("-genkeypair -alias carl1 -keyalg RSA -sigalg SHA1withRSA -keysize 1024 -validity 365 -keystore carl1.keystore");
		//列出密钥库中的条目
		//execCommand("-list -keystore carl1.keystore");
		//从密钥库导出公钥到证书
		//execCommand("-export -alias carl1 -file carl1.crt -keystore carl1.keystore");
		//打印证书内容
		execCommand("-printcert -file carl1.crt");
// System.out.println(getStrFromKey(getPublicKeyFromCert(getCertFromKeyStore("JKS", "carl.keystore", "qq2476056494", "carl"))));
// System.out.println(getStrFromKey(getPublicKeyFromCert(getCert("carl.crt"))));
// System.out.println(getStrFromKey(getPrivateKeyFromKeyStore("JKS", "carl.keystore", "qq2476056494", "carl","qq2476056494")));
	}
	
	/** * 打印keytool的所有命令 */
	public static void printAllCommand(){ 
   
		try { 
   
			Main.main(("-help").split("\\s"));
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
	}
	
	/** * 打印keytool的指定命令帮助信息 * @param commandName */
	public static void printCommandHelp(String commandName){ 
   
		try { 
   
			Main.main(("-"+commandName + " -help").split("\\s"));
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
	}
	
	/** * 通用的命令执行 * @param command */
	public static void execCommand(String command){ 
   
		try { 
   
			Main.main((command).split("\\s"));
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
	}
	
	/** * 获取密钥库中的证书 * @param keyStoreType 密钥库的条目类型,-list可以查看 * @param keyStorePath 密钥库的文件路径 * @param keyStorePass 密钥库密码 * @param alias 条目别名 * @return */
	public static Certificate getCertFromKeyStore(String keyStoreType,String keyStorePath,String keyStorePass,String alias){ 
   
		try { 
   
			//因为生成证书的类型为JKS 也有其他的格式 -list可以查看密钥库的条目类型
			KeyStore keyStore = KeyStore.getInstance(keyStoreType);  
			//读取keystore文件转换为keystore密钥库对象 
			FileInputStream fis = new FileInputStream(keyStorePath);  
			//该密钥库的密码
			keyStore.load(fis, keyStorePass.toCharArray());  
			fis.close();  
			// 从keystore中获取证书然后进一步获取公钥
			Certificate certificate = keyStore.getCertificate(alias);
			return certificate;
		} catch (KeyStoreException e) { 
   
			e.printStackTrace();
		} catch (FileNotFoundException e) { 
   
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) { 
   
			e.printStackTrace();
		} catch (CertificateException e) { 
   
			e.printStackTrace();
		} catch (IOException e) { 
   
			e.printStackTrace();
		}
        return null;
	}
	
	
	/** * 直接读取证书 * @param certPath 证书目录 * @return */
	public static Certificate getCert(String certPath){ 
   
		try { 
   
			//证书类型只支持X.509
			CertificateFactory factory = CertificateFactory.getInstance("X.509");
			// 取得证书文件流
			FileInputStream inputStream = new FileInputStream(certPath);
			// 生成证书
			Certificate certificate = factory.generateCertificate(inputStream);
			inputStream.close();
			return certificate;
		} catch (CertificateException e) { 
   
			e.printStackTrace();
		} catch (FileNotFoundException e) { 
   
			e.printStackTrace();
		} catch (IOException e) { 
   
			e.printStackTrace();
		}
		return null;
	}
	
	
	
	/** * 从证书读取公钥,java只支持X509Certificate * @param certificate * @return */
	public static PublicKey getPublicKeyFromCert(Certificate certificate){ 
   
		 //读取公钥对象 
		X509Certificate x509Certificate = (X509Certificate) certificate;
		PublicKey publicKey = certificate.getPublicKey();
		System.out.println("证书算法:" + x509Certificate.getSigAlgName());
		System.out.println("公钥算法:" + publicKey.getAlgorithm());
		return publicKey;
	}
	
 
	/** * 获取密钥库中的私钥内容 * @param keyStoreType 密钥库的条目类型,keytool -list可以查看 * @param keyStorePath 密钥库的文件路径 * @param keyStorePass 密钥库密码 * @param alias 条目别名 * @param aliasPass 条目密码 * @return */
	public static PrivateKey getPrivateKeyFromKeyStore(String keyStoreType,String keyStorePath,String keyStorePass,String alias,String aliasPass){ 
   
		try { 
   
			//因为生成证书的类型为JKS 也有其他的格式 -list可以查看密钥库的条目类型
			KeyStore keyStore = KeyStore.getInstance(keyStoreType);  
			//读取keystore文件转换为keystore密钥库对象 
			FileInputStream fis = new FileInputStream(keyStorePath);  
			//该密钥库的密码
			keyStore.load(fis, keyStorePass.toCharArray());  
			fis.close();  
			PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, aliasPass.toCharArray());
			return privateKey;
		} catch (KeyStoreException e) { 
   
			e.printStackTrace();
		} catch (FileNotFoundException e) { 
   
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) { 
   
			e.printStackTrace();
		} catch (CertificateException e) { 
   
			e.printStackTrace();
		} catch (IOException e) { 
   
			e.printStackTrace();
		} catch (UnrecoverableKeyException e) { 
   
			e.printStackTrace();
		}
        return null;
	}
	
	/** * 从key获取密钥串 * @param key * @return base64编码处理后的字符串 */
	public static String getStrFromKey(Key key){ 
   
		//64位编码处理
		return Base64.getEncoder().encodeToString(key.getEncoded());
	}
	
	
	/** * 从字符串还原回key * @param encodedKey base64编码处理后的字符串 * @param algorithm 指定算法 * @return 还原的key */
	public static SecretKey getKeyFromStr(String encodedKey,String algorithm){ 
   
		// decode the base64 encoded string
		byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
		// rebuild key using SecretKeySpec
		SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, algorithm); 
		return originalKey;
	}
}

至此,终于解决了。心情瞬间舒畅!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/24372.html

(0)
上一篇 2023-08-23 21:00
下一篇 2023-08-24 15:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信