zoukankan      html  css  js  c++  java
  • 解决Linux下AES解密失败

            前段时间,用了个AES加密解密的方法,详见上篇博客AES加密解密

    加解密方法在window上測试的时候没有出现不论什么问题。将加密过程放在安卓上。解密公布到Linuxserver的时候,安卓将加密的结果传到Linux上解密的时候却总是失败,让用户不能成功登录。经过检查,測试后。发现AES在Linux上解密失败,出现错误:

            javax.crypto.BadPaddingException: Given final block not properly padded

    如今来回想下自己的解决思路:

            加密过程是在安卓上,解密是在Linu上,会不会是由于环境的不同,在加密过程中产生的二进制和在解密过程中产生的二进制不一样呢?但是在经过联调后,比对二进制。发现没有问题。那问题是在哪里呢?

           继续联调, 细致比对加密和解密过程中每一步产生的结果。发现了问题:

    Linux解密端:

           发现这里的cipher下的 firstService是有值的。

            


    安卓加密端:

           发现这里的cipher下的 firstService是没有值的。

           


    百度后发现:

           加密解密方法的唯一区别是Cipher对象的模式不一样,这就排除了程序写错的可能性。

    由于错误信息是在宜昌中出现的。其大概意思是:提供的字块不符合填补的。什么意思呢?原来在用加密的时候,最后一位长度不足,它会自己主动补足,那么在我们进行字节数组到字串的转化过程中,能够把它填补的不可见字符改变了。所以系统抛出异常。

            问题找到,怎么解决呢?方式例如以下:

    package ICT.base.rest.services.app;
    
    import java.io.UnsupportedEncodingException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.KeyGenerator;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public class AESDecodeUtils {
    	public static void main(String[] args) {
    
    		String content = "g25";
    		String pwd = "8182838485";
    		String addPwd = "123456";
    
    		// 加密
    		System.out.println("加密前content:" + content);
    		byte[] enAccount = encrypt(content, addPwd);
    		byte[] enPwd = encrypt(pwd, addPwd);
    		String encryptResultStr = parseByte2HexStr(enAccount);
    		String parseByte2HexStr2 = parseByte2HexStr(enPwd);
    		System.out.println("加密后content:" + encryptResultStr);
    
    		// 解密 ——账号/身份证号
    		byte[] accountFrom = AESDecodeUtils.parseHexStr2Byte(encryptResultStr);
    		byte[] deAccount = AESDecodeUtils.decrypt(accountFrom, addPwd);
    		String userAccount = new String(deAccount);
    		System.out.println("解密后content:" + userAccount);
    		// 解密——密码
    		byte[] pwdFrom = AESDecodeUtils.parseHexStr2Byte(parseByte2HexStr2);
    		byte[] deUserPwd = AESDecodeUtils.decrypt(pwdFrom, addPwd);
    		String userPwd = new String(deUserPwd);
    		// System.out.println(userPwd);
    	}
    
    	/**
    	 * AES加密
    	 * 
    	 * @param content
    	 *            要加密的内容
    	 * @param password
    	 *            加密使用的密钥
    	 * @return 加密后的字节数组
    	 */
    	public static byte[] encrypt(String content, String password) {
    		SecureRandom random = null;
    		try {
    			<span style="color:#ff0000;">random = SecureRandom.getInstance("SHA1PRNG");
    			random.setSeed(password.getBytes());</span>
    		} catch (NoSuchAlgorithmException e1) {
    			e1.printStackTrace();
    		}
    
    		try {
    			KeyGenerator kgen = KeyGenerator.getInstance("AES");
    			// kgen.init(128, new SecureRandom(password.getBytes()));
    			<span style="color:#ff0000;">kgen.init(128, random);</span>
    			SecretKey secretKey = kgen.generateKey();
    			byte[] enCodeFormat = secretKey.getEncoded();
    			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
    			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
    			byte[] byteContent = content.getBytes("utf-8");
    			cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
    			byte[] result = cipher.doFinal(byteContent);
    			return result; // 加密
    		} 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;
    	}
    
    	/**
    	 * 将二进制转换成16进制 加密
    	 * 
    	 * @param buf
    	 * @return
    	 */
    	public static String parseByte2HexStr(byte buf[]) {
    		StringBuffer sb = new StringBuffer();
    		for (int i = 0; i < buf.length; i++) {
    			String hex = Integer.toHexString(buf[i] & 0xFF);
    			if (hex.length() == 1) {
    				hex = '0' + hex;
    			}
    			sb.append(hex.toUpperCase());
    		}
    		return sb.toString();
    	}
    
    	/**
    	 * 解密
    	 * 
    	 * @param content
    	 *            待解密内容
    	 * @param password
    	 *            解密密钥
    	 * @return
    	 */
    	public static byte[] decrypt(byte[] content, String password) {
    		SecureRandom random = null;
    		try {
    			<span style="color:#ff0000;">random = SecureRandom.getInstance("SHA1PRNG");
    			random.setSeed(password.getBytes());</span>
    		} catch (NoSuchAlgorithmException e1) {
    			e1.printStackTrace();
    		}
    		try {
    			KeyGenerator kgen = KeyGenerator.getInstance("AES");
    			// kgen.init(128, new SecureRandom(password.getBytes()));
    			<span style="color:#ff0000;">kgen.init(128, random);</span>
    			SecretKey secretKey = kgen.generateKey();
    			byte[] enCodeFormat = secretKey.getEncoded();
    			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
    			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
    			cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
    			byte[] result = cipher.doFinal(content);
    			return result; // 加密
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    		} catch (NoSuchPaddingException e) {
    			e.printStackTrace();
    		} catch (InvalidKeyException e) {
    			e.printStackTrace();
    		} catch (IllegalBlockSizeException e) {
    			e.printStackTrace();
    		} catch (BadPaddingException e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    
    	/**
    	 * 将16进制转换为二进制
    	 * 
    	 * @param hexStr
    	 * @return
    	 */
    	public static byte[] parseHexStr2Byte(String hexStr) {
    		if (hexStr.length() < 1)
    			return null;
    		byte[] result = new byte[hexStr.length() / 2];
    		for (int i = 0; i < hexStr.length() / 2; i++) {
    			int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
    			int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
    					16);
    			result[i] = (byte) (high * 16 + low);
    		}
    		return result;
    	}
    }
    


     执行结果:

            


    将加密放到安卓端。解密放大Linux上后,例如以下:

           此时cipher下的 firstService不再是Null,都有了值

    安卓加密端:

           

    Linux解密端:

           


    总结:

          AES是对称加密,解密端改变解密过程。相同,加密端的加密过程也会改变。无论怎么着,调程序还是得要有耐心。用一个东西,其简单主要的原理还是要知道的。




           

            


           

  • 相关阅读:
    python 包管理工具 pip 的配置
    Python 变量作用域 LEGB (下)—— Enclosing function locals
    Python 变量作用域 LEGB (上)—— Local,Global,Builtin
    2020 Java 面试题 小结 (答案慢慢补上,有错误请指出)
    mysql 根据日期(date)做年,月,日分组统计查询
    jvm指令
    正则表达式 分割地址 获取省市区详细地址
    .Net 异常记录
    WCF设计服务协议(一)
    plsql ORA-01789:查询块具有不正确的结果列数
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/6789270.html
Copyright © 2011-2022 走看看