美文网首页
ase 加密

ase 加密

作者: 情深元浅 | 来源:发表于2020-11-01 20:38 被阅读0次

    昨天遇到一个加密的东西,解决问题的过程异常艰辛
    要求是
    AES256-CBC-PKCS7Padding加密 base64输出
    代码老大之前有给过我一份,让我参考一下。
    毫无疑问的,我拿来就跑demo,当时是在android studio上跑,毫无疑问失败了,jdk的版本用的是开源的,不是oracle的。demo也没有好好看
    当时电脑有点卡,键盘好像也有点问题,拷贝东西的时候不多按几下c键,东西可能拷贝不下来。

    遇到的第一个问题是 java.security.InvalidKeyException:illegal Key Size
    解决方案:我换了个jdk,然后下载了local_policy.jar和US_export_policy.jar覆盖本地的包

    遇到的第二个问题是生成的密文不对,解不出来。然后怀疑给的代码有问题,网上找各种版本。Google,stackoverflow。他们建议是把PKCS7Padding换成PKCS5Padding。这个和需求有悖。那就只能找别人实现了的,这个相当耗时,时间久了,感觉不对就去老大那里看他那加解密是怎么做的。他那边的做法和我一样只是不同的语言实现的。这时候我回到原来的代码上,一阵狂改,感觉没用的全都注释。老大看过看我的代码,发现上面的key,和iv是一样的,我当时就懵逼了

    最后一个问题:不多说,自己犯傻

    深深鄙视贴代码贴一半的人

    import java.nio.charset.Charset;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Random;
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    //这个类可以自己写,base64网上一大堆 本文用的是apache的 commons-codec
    import org.apache.commons.codec.binary.Base64;
    
    /**
    
     * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
     * <ol>
     * <li>在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
     * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124
     * .html
     * jdk 8
     * http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
     * </li>
     * <li>下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt</li>
     * <li>如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件</li>
     * <li>如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件</li>
     * </ol>
     */
    public class ASE {
        static Charset CHARSET = Charset.forName("utf-8");
        Base64 base64 = new Base64();
        byte[] aesKey = "1q2w3e4rfdsaffdsa343234d".getBytes();
        byte[] iv = "0316030405060709".getBytes();
        static int BLOCK_SIZE = 32;
    
        // 生成4个字节的网络字节序
        byte[] getNetworkBytesOrder(int sourceNumber) {
            byte[] orderBytes = new byte[4];
            orderBytes[3] = (byte) (sourceNumber & 0xFF);
            orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
            orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
            orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
            return orderBytes;
        }
    
        // 还原4个字节的网络字节序
        int recoverNetworkBytesOrder(byte[] orderBytes) {
            int sourceNumber = 0;
            for (int i = 0; i < 4; i++) {
                sourceNumber <<= 8;
                sourceNumber |= orderBytes[i] & 0xff;
            }
            return sourceNumber;
        }
    
        // 随机生成16位字符串
        String getRandomStr() {
            String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            Random random = new Random();
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < 16; i++) {
                int number = random.nextInt(base.length());
                sb.append(base.charAt(number));
            }
            return sb.toString();
        }
    
        /**
         * 对明文进行加密.
         * 
         * @param text
         *            需要加密的明文
         * @return 加密后base64编码的字符串
         * @throws AesException
         *             aes加密失败
         */
        String encrypt(String text) throws AesException {
            ByteGroup byteCollector = new ByteGroup();
            byte[] randomStrBytes = getRandomStr().getBytes(CHARSET);
            byte[] textBytes = text.getBytes(CHARSET);
            byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
    
            // randomStr + networkBytesOrder + text
            byteCollector.addBytes(randomStrBytes);
            byteCollector.addBytes(networkBytesOrder);
            byteCollector.addBytes(textBytes);
    
            // ... + pad: 使用自定义的填充方式对明文进行补位填充
            byte[] padBytes = encode(byteCollector.size());
            byteCollector.addBytes(padBytes);
    
            // 获得最终的字节流, 未加密
            byte[] unencrypted = byteCollector.toBytes();
    
            try {
                // 设置加密模式为AES的CBC模式
                Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
                SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
                IvParameterSpec ivs = new IvParameterSpec(iv, 0, 16);
                cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivs);
    
                // 加密
                byte[] encrypted = cipher.doFinal(unencrypted);
    
                // 使用BASE64对加密后的字符串进行编码
                String base64Encrypted = base64.encodeToString(encrypted);
    
                return base64Encrypted;
            } catch (Exception e) {
                e.printStackTrace();
                throw new AesException(AesException.EncryptAESError);
            }
        }
    
        /**
         * 对密文进行解密.
         * 
         * @param text
         *            需要解密的密文
         * @return 解密得到的明文
         * @throws AesException
         *             aes解密失败
         */
        String decrypt(String text) throws AesException {
            byte[] original;
            try {
                // 设置解密模式为AES的CBC模式
                Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
                SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
                IvParameterSpec ivs = new IvParameterSpec(Arrays.copyOfRange(iv, 0, 16));
                cipher.init(Cipher.DECRYPT_MODE, key_spec, ivs);
    
                // 使用BASE64对密文进行解码
                byte[] encrypted = Base64.decodeBase64(text);
    
                // 解密
                original = cipher.doFinal(encrypted);
            } catch (Exception e) {
                e.printStackTrace();
                throw new AesException(AesException.DecryptAESError);
            }
    
            String xmlContent;
            try {
                // 去除补位字符
                byte[] bytes = decode(original);
    
                // 分离16位随机字符串,网络字节序和AppId
                byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
    
                int xmlLength = recoverNetworkBytesOrder(networkOrder);
    
                xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
            } catch (Exception e) {
                e.printStackTrace();
                throw new AesException(AesException.IllegalBuffer);
            }
    
            return xmlContent;
    
        }
    
        /**
         * 获得对明文进行补位填充的字节.
         * 
         * @param count
         *            需要进行填充补位操作的明文字节个数
         * @return 补齐用的字节数组
         */
        static byte[] encode(int count) {
            // 计算需要填充的位数
            int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
            if (amountToPad == 0) {
                amountToPad = BLOCK_SIZE;
            }
            // 获得补位所用的字符
            char padChr = chr(amountToPad);
            String tmp = new String();
            for (int index = 0; index < amountToPad; index++) {
                tmp += padChr;
            }
            return tmp.getBytes(CHARSET);
        }
    
        /**
         * 删除解密后明文的补位字符
         * 
         * @param decrypted
         *            解密后的明文
         * @return 删除补位字符后的明文
         */
        static byte[] decode(byte[] decrypted) {
            int pad = (int) decrypted[decrypted.length - 1];
            if (pad < 1 || pad > 32) {
                pad = 0;
            }
            return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
        }
    
        /**
         * 将数字转化成ASCII码对应的字符,用于对明文进行补码
         * 
         * @param a
         *            需要转化的数字
         * @return 转化得到的字符
         */
        static char chr(int a) {
            byte target = (byte) (a & 0xFF);
            return (char) target;
        }
    
        class ByteGroup {
            ArrayList<Byte> byteContainer = new ArrayList<Byte>();
    
            public byte[] toBytes() {
                byte[] bytes = new byte[byteContainer.size()];
                for (int i = 0; i < byteContainer.size(); i++) {
                    bytes[i] = byteContainer.get(i);
                }
                return bytes;
            }
    
            public ByteGroup addBytes(byte[] bytes) {
                for (byte b : bytes) {
                    byteContainer.add(b);
                }
                return this;
            }
    
            public int size() {
                return byteContainer.size();
            }
        }
        
        /***
         * 抄代码注意顶部的提示
         * key和iv别拷贝的时候仔细点,别搞错了
         * 
         * @param args
         */
        public static void main(String[] args) {
            String str = "11111";
            ASE ase = new ASE();
            String aseword = null;
            try {
                aseword = ase.encrypt(str);
                System.out.println(aseword);
                
                String decryptString =  ase.decrypt(aseword);
                
                System.out.println(decryptString);
            } catch (AesException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
        
    }
    

    exception类

    
    public class AesException extends Exception {
    
        private static final long serialVersionUID = 1L;
        public final static int OK = 0;
        
        public final static int EncryptAESError = -40006;
        public final static int DecryptAESError = -40007;
        public final static int IllegalBuffer = -40008;
    
        private int code;
    
        private static String getMessage(int code) {
            switch (code) {
            case EncryptAESError:
                return "aes加密失败";
            case DecryptAESError:
                return "aes解密失败";
            case IllegalBuffer:
                return "解密后得到的buffer非法";
            default:
                return null; // cannot be
            }
        }
    
        public int getCode() {
            return code;
        }
    
        AesException(int code) {
            super(getMessage(code));
            this.code = code;
        }
    
    }
    

    相关文章

      网友评论

          本文标题:ase 加密

          本文链接:https://www.haomeiwen.com/subject/ktpuvktx.html