diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeAppNetWorkManager.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeAppNetWorkManager.kt index 1c43f8c92a..55d6fb2daa 100644 --- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeAppNetWorkManager.kt +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeAppNetWorkManager.kt @@ -196,6 +196,10 @@ class UpgradeAppNetWorkManager private constructor() { Log.d(TAG,"MyFLow网络请求返回:${response}") SharedPrefsMgr.getInstance().putString(SharedPrefsConstants.APP_UPGRADE_CONTENT_MyFlow, if (info.result != null) response + "--vin:$tempVin" else "info.result == null --vin:$tempVin --type:$type") if (info.data != null) { + if(info.data.encKey!=null&&info.data.encMd5!=null){ + val fileMd5 = AesEcbBase64Util.decryptFromBase64(info.data.encMd5,info.data.encKey) + SharedPrefsMgr.getInstance().putString(SharedPrefsConstants.APP_UPGRADE_CONTENT_MYFLOW_CHECKMD5,"${info.data.fileAddr}_$fileMd5") + } runCatching { block?.invoke(true, response) } diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeManager.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeManager.kt index 171afbabde..2e62a5c43a 100644 --- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeManager.kt +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/upgrade/UpgradeManager.kt @@ -6,6 +6,8 @@ import com.mogo.eagle.core.data.constants.MogoServicePaths import com.mogo.eagle.core.function.api.upgrade.IMoGoUpgradeProvider import com.mogo.eagle.core.function.call.base.CallerBase import com.elegant.utils.UiThreadHandler +import com.mogo.commons.constants.SharedPrefsConstants +import com.mogo.commons.storage.SharedPrefsMgr import com.mogo.eagle.core.data.obu.MogoObuConst import com.mogo.eagle.core.function.api.devatools.IMogoDevaToolsUpgradeListener import com.mogo.eagle.core.function.api.devatools.download.* @@ -172,6 +174,19 @@ class UpgradeManager : IDownloadListener { } } else { val apk = File(localPath) + val fileMd5WithUrl = SharedPrefsMgr.getInstance().getString(SharedPrefsConstants.APP_UPGRADE_CONTENT_MYFLOW_CHECKMD5) + if(fileMd5WithUrl.startsWith(downloadUrl)) { + Md5Util.getMd5FromFile(apk)?.let {fileMd5-> + if(fileMd5WithUrl.endsWith(fileMd5)){ + Logger.w(TAG, "md5校验通过...") + }else{ + upgradeProvider?.recordTargetMd5CheckFailed("${StringUtils.getString(com.mogo.eagle.core.widget.R.string.module_core_compound_apk_md5_check_failed)}:[server_target_md5: ${fileMd5WithUrl}, file_md5: ${fileMd5}]") + Logger.w(TAG, "md5校验失败...") +// throw AssertionError("md5校验失败:[target:${patchInfo.targetMd5}]") + throw AssertionError("${StringUtils.getString(com.mogo.eagle.core.widget.R.string.module_core_md5_check_failed)}:[target:${fileMd5WithUrl}]") + } + } + } upgradeProvider?.recordInstallStart() withContext(Dispatchers.Main) { ApkInstaller.installApp(Utils.getApp(), apk) { code, reason -> diff --git a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/bindingcar/AppInfoMyFlow.kt b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/bindingcar/AppInfoMyFlow.kt index 47262a0a54..1cafaa47fc 100644 --- a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/bindingcar/AppInfoMyFlow.kt +++ b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/bindingcar/AppInfoMyFlow.kt @@ -11,7 +11,9 @@ data class AppInfoMyFlow( val sn: String, val taskItemId: Int?, val versionCode: Int?, - val versionNo: String + val versionNo: String?, + val encMd5: String?, + val encKey: String?, ){ fun toAppInfo():AppInfo{ val appInfo = AppInfo() diff --git a/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/util/AesEcbBase64Util.java b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/util/AesEcbBase64Util.java new file mode 100644 index 0000000000..3ba4894290 --- /dev/null +++ b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/util/AesEcbBase64Util.java @@ -0,0 +1,110 @@ +package com.mogo.eagle.core.utilcode.util; + +import android.util.Base64; + +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + +/** + * Android平台专用的AES-ECB Base64加解密工具类 + * 适配Android的Base64工具类,优化异常处理 + */ +public class AesEcbBase64Util { + + // 测试方法(Android中建议在Activity/Fragment/ViewModel中调用) + public static void testEncryptDecrypt() { + String plainText = "41a59bbbb04b4f02b03672f1c177d4cc"; + String keyBase64 = "3OMe6b0jgPRIgngYxRdeGA=="; + + String encryptResult = AesEcbBase64Util.encryptToBase64(plainText, keyBase64); + String decryptResult = AesEcbBase64Util.decryptFromBase64(encryptResult, keyBase64); + + System.out.println("加密结果:" + encryptResult); + System.out.println("解密结果:" + decryptResult); + } + + private static final String ALGO = "AES"; + private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; + private static final int KEY_LEN_BYTES = 16; + + // 私有化构造方法,防止实例化 + private AesEcbBase64Util() { + } + + /** + * 生成随机的AES密钥(Base64编码) + * @return 16字节密钥的Base64字符串 + */ + public static String randomKeyBase64() { + byte[] key = new byte[KEY_LEN_BYTES]; + new SecureRandom().nextBytes(key); + // 替换为Android的Base64工具类,使用默认编码模式 + return Base64.encodeToString(key, Base64.NO_WRAP); + } + + /** + * AES加密并输出Base64编码结果 + * @param plaintext 明文 + * @param keyBase64 Base64编码的16字节AES密钥 + * @return Base64编码的密文 + * @throws IllegalArgumentException 密钥长度错误时抛出 + * @throws IllegalStateException 加密失败时抛出 + */ + public static String encryptToBase64(String plaintext, String keyBase64) { + try { + // 解码Base64密钥 + byte[] key = Base64.decode(keyBase64, Base64.NO_WRAP); + if (key.length != KEY_LEN_BYTES) { + throw new IllegalArgumentException("无效的AES密钥长度: " + key.length + ",必须为16字节"); + } + + // 初始化加密器 + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, ALGO)); + + // 处理空明文 + byte[] plainBytes = plaintext == null ? new byte[0] : plaintext.getBytes(StandardCharsets.UTF_8); + byte[] encryptBytes = cipher.doFinal(plainBytes); + + // 加密结果转Base64 + return Base64.encodeToString(encryptBytes, Base64.NO_WRAP); + } catch (GeneralSecurityException e) { + throw new IllegalStateException("AES加密失败", e); + } + } + + /** + * 从Base64密文解密出明文 + * @param ciphertextBase64 Base64编码的密文 + * @param keyBase64 Base64编码的16字节AES密钥 + * @return 解密后的明文 + * @throws IllegalArgumentException 密钥长度错误时抛出 + * @throws IllegalStateException 解密失败时抛出 + */ + public static String decryptFromBase64(String ciphertextBase64, String keyBase64) { + try { + // 解码Base64密钥 + byte[] key = Base64.decode(keyBase64, Base64.NO_WRAP); + if (key.length != KEY_LEN_BYTES) { + throw new IllegalArgumentException("无效的AES密钥长度: " + key.length + ",必须为16字节"); + } + + // 解码Base64密文 + byte[] cipherBytes = Base64.decode(ciphertextBase64, Base64.NO_WRAP); + + // 初始化解密器 + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, ALGO)); + + // 解密并转字符串 + byte[] plainBytes = cipher.doFinal(cipherBytes); + return new String(plainBytes, StandardCharsets.UTF_8); + } catch (GeneralSecurityException e) { + throw new IllegalStateException("AES解密失败", e); + } + } +} \ No newline at end of file diff --git a/foudations/mogo-commons/src/main/java/com/mogo/commons/constants/SharedPrefsConstants.java b/foudations/mogo-commons/src/main/java/com/mogo/commons/constants/SharedPrefsConstants.java index 57b1c122c6..c5988da660 100644 --- a/foudations/mogo-commons/src/main/java/com/mogo/commons/constants/SharedPrefsConstants.java +++ b/foudations/mogo-commons/src/main/java/com/mogo/commons/constants/SharedPrefsConstants.java @@ -18,6 +18,7 @@ public class SharedPrefsConstants { public static final String HOST_ADDRESS_MyFLow = "host_address_update_myflow"; public static final String APP_UPGRADE_CONTENT = "app_upgrade_content"; public static final String APP_UPGRADE_CONTENT_MyFlow = "app_upgrade_content_myflow"; + public static final String APP_UPGRADE_CONTENT_MYFLOW_CHECKMD5 = "app_upgrade_content_myflow_check_md5"; public static final String APP_MAC = "app_mac";