JAVA 3DES加密 ECB模式 ZeroPadding填充

之前网上找了一堆也不能用 有幸找到了这个 在线工具比对后发现是加密模式的问题 网上大多数DEMO用的是CBC模式 而我们项目用的是ECB模式 代码如下

工具类CipherUtil

package com.ruidde.vis.utils;

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;
/**
 * @author feng
 * @version 1.0
 * @date 2019/11/8 17:18
 */
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 = "SP0000011234567890123456";
        String encryptWithDESCEBZeroPading = encryptWithDESCEBZeroPading(deskey, "userID=itvtest1$userToken=03168303891651601516521016112900$timeStamp=20130905100000$optFlag=GAME$orderTransactionID=sp000001678943065000001");
        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

package com.ruidde.vis.utils;

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 feng
 * @version 1.0
 * @date 2019/11/8 17:18
 */
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;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值