Xiaofeng_Go 2021-09-28 10:31 采纳率: 0%
浏览 58

Android AES加密 偶现解密后乱码 排除明文中文乱码 还有什么其他的原因?

这个问题已经困扰了我1个多星期了,身边的同事和朋友问了个遍,也没找出问题的原因,很焦急,希望可以得到大家的帮助,万分感谢!

现在情况是,我在做数据加密,我写了个拦截器,讲post请求里的参数转换成jsonString,在将jsonString进行AES加密,将加密后的string放到post请求的body中去,再发送请求。加密的key是我会向后台请求得到key,保证前后端key统一。出现的问题是,会偶现,传给后台的密文,后台解开是乱码,然后我拿相同的key去解开这个密文得到的也是乱码。
出现问题的,原始明文是[{"lat":34.1920461,"lng":-118.3070839}],没有什么特殊的字符,然后我传给后台的错误密文是Tib6Iy57QTnd/Gc6ct37Lb8dPqqcH7bGPgCmVV14pv7QmB3FdvqdDuEeBA+/3yMc,然后这段对应的key是0afaca3ec1be4f30b42b3c56f5800ffa,解开的效果是一大堆乱码。然后我用这个明文再加上key,用我的加密工具类再次进行多次加密得到的都是dnoRtLTWkrLBuP1JiZf+77IZvHrVT+YXIA0gH6M1nLrVIlrXtgOz2ebaiYDa6Yo2

下面是我网络请求拦截器请求部分的实现,网络框架用的retrofit

img

现在的线索有一下几条
1、我压测了我的加密工具,相同的key和明文,进行几万次加密,得到的密文都是相同的,不会出现不同
2、后台接收到的那个错误密文比正确密文短了一半
3、错误密文的通过base64编码得到的byte数组中 有很多 ed ef bd,百度查说是无效字符占位
4、我跟后台用的加密工具类完全相同,只有base64的包不一样,我用的android
5、主要是那个密文我自己解开也是乱码

下面是我的加密工具类的代码

package com.truckerpath.services.backend.security;

import android.util.Base64;
import android.util.Log;

import com.truckerpath.managers.sign.ServerDateManager;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * AES 对称加密算法,加解密工具类
 */
public class SecurityAESUtils {
    /**
     * 加密算法
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * AES 的 密钥长度,32 字节,范围:16 - 32 字节
     */
    public static final int SECRET_KEY_LENGTH = 32;

    /**
     * 字符编码
     */
    private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;

    /**
     * 秘钥长度不足 16 个字节时,默认填充位数
     */
    private static final String DEFAULT_VALUE = "0";
    /**
     * 加解密算法/工作模式/填充方式
     */
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

    private static String secretKey;
    private static Long securityKeyTime = 0L;
    public static Boolean isEncrypt = true;

    public static boolean isExpireKey(){
        if (securityKeyTime <= ServerDateManager.getInstance().getSynDate()){
            return true;
        }
        return  false;
    }

    public static void setSecretKey(String secretKey, Long time) {
        SecurityAESUtils.secretKey = secretKey;
        securityKeyTime = time;
        Log.i("SecurityInterceptor", "keySecurity = " + secretKey);
    }

    /**
     * AES 加密
     *
     * @param data      待加密内容
     * @return 返回Base64转码后的加密数据
     */
    public static String encrypt(String data) {
        try {
            //创建密码器
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            //初始化为加密密码器
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
            byte[] encryptByte = cipher.doFinal(data.getBytes(CHARSET_UTF8));
            // 将加密以后的数据进行 Base64 编码
            return base64Encode(encryptByte);
        } catch (Exception e) {
            handleException(e);
        }
        return null;
    }

    /**
     * AES 解密
     *
     * @param base64Data 加密的密文 Base64 字符串
     */
    public static String decrypt(String base64Data) {
        try {
            byte[] data = base64Decode(base64Data);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            //设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey());
            //执行解密操作
            byte[] result = cipher.doFinal(data);
            return new String(result, CHARSET_UTF8);
        } catch (Exception e) {
            handleException(e);
        }
        return null;
    }

    /**
     * 使用密码获取 AES 秘钥
     */
    public static SecretKeySpec getSecretKey() {
        secretKey = toMakeKey(SECRET_KEY_LENGTH, DEFAULT_VALUE);
        return new SecretKeySpec(secretKey.getBytes(CHARSET_UTF8), KEY_ALGORITHM);
    }

    /**
     * 如果 AES 的密钥小于 {@code length} 的长度,就对秘钥进行补位,保证秘钥安全。
     *
     * @param length    密钥应有的长度
     * @param text      默认补的文本
     * @return 密钥
     */
    private static String toMakeKey(int length, String text) {
        // 获取密钥长度
        int strLen = secretKey.length();
        // 判断长度是否小于应有的长度
        if (strLen < length) {
            // 补全位数
            StringBuilder builder = new StringBuilder();
            // 将key添加至builder中
            builder.append(secretKey);
            // 遍历添加默认文本
            for (int i = 0; i < length - strLen; i++) {
                builder.append(text);
            }
            // 赋值
            secretKey = builder.toString();
        }
        return secretKey;
    }

    /**
     * 将 Base64 字符串 解码成 字节数组
     */
    public static byte[] base64Decode(String data) {
        return Base64.decode(data,Base64.NO_WRAP);
    }

    /**
     * 将 字节数组 转换成 Base64 编码
     */
    public static String base64Encode(byte[] data) {
        return Base64.encodeToString(data, Base64.NO_WRAP);
    }

    /**
     * 处理异常
     */
    private static void handleException(Exception e) {
        e.printStackTrace();
        Log.i("SecurityInterceptor","SecurityAESUtils  erro = " + e.getMessage());
    }
}

以上是我的问题描述,有不清楚的地方可以问我,真的很焦急,希望可以得到大家的帮助,能说出导致这个问题的原因也可以,还有麻烦大家给解决方案时,说一下为啥要这么改,什么原因导致的问题所以这么改。因为是偶现问题,找不到必现的方式,所以不好验证,必须知道原因才好去验证。谢谢

  • 写回答

1条回答 默认 最新

  • baidu_30233079 2021-09-28 10:59
    关注

    java里面多数都是传引用的,看样子好像数据在加密、base64转换过程遭到破坏了,检查一个数据共享和互斥方面的问题

    评论

报告相同问题?

问题事件

  • 创建了问题 9月28日

悬赏问题

  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的