ArrayList<E>.<init> line: not available

 

之前调试java源码时,发现无法定位到源码,如图1.1和图1.2


                                         图1.1     

       

                                                                                                                     

                                                                    图1.2

但仔细核查一遍后,确实都已关联源码,如图2,但调试仍断不上

  

       

                                          图2

         

        不断折腾发现,更换成jdk安装目录下的jre问题就解决了,如图3.1,而不是安装jdk时那个安装专用的jre,如图3.2和3.3


        

                                            图3.1

   

                   

                                                                       图3.2

                  

                       

                                                                     图3.3

             更换JRE效果如图4

                     

                                         图4

          重新调试就可正确断到断点处了,如图5.1和图5.2

        

                                          图5.1


        

                                        图5.2


            虽然问题解决了,但仍有不少疑问?

            1、在eclipse上都关联了源码,为啥选jdk下的jre可以关联上,而专用的jre不行?

                 这个与eclipse具体的插件实现有关,比如在该插件实现中需要jdk bin目录一下的一个命令,而运行期环境jre没有(仅仅是个人猜想),具体原因未知

            2、eclipse中jvm启动加载jre的顺序

                 http://blog.youkuaiyun.com/teedry/article/details/6666850

            3、eclipse只需要jre环境即可打开,jre下又无javac.exe,那eclipse是如何编译java源代码的呢?

                 这个是由eclipse的一个核心组建JDT来负责编译的,JDT为Java Development Tool


         



     

        

16:22:53 PIT >> INFO : --------------------------------------------------------------------------- 16:22:53 PIT >> INFO : Enabled (+) and disabled (-) features. 16:22:53 PIT >> INFO : ----------------------------------------- 16:22:53 PIT >> INFO : +FANN Filters mutations in classes and methods with matching annotations of class or runtime retention 16:22:53 PIT >> INFO : [annotation] Annotation to avoid (full package name not required) 16:22:53 PIT >> INFO : +FENUM Filters mutations in enum constructors 16:22:53 PIT >> INFO : +FFBLOCK Filters mutations in code duplicated by finally block inlining 16:22:53 PIT >> INFO : +FFEACH Filters mutations in compiler generated code that implements for each loops 16:22:53 PIT >> INFO : +FFLOOP Filters any mutations to increments in for loops as they may cause timeouts 16:22:53 PIT >> INFO : +FINFINC Filters mutations to increments that may cause infinite loops 16:22:53 PIT >> INFO : +FINFIT Filters mutations that may cause infinite loops by removing calls to iterator.next 16:22:53 PIT >> INFO : +FINULL Filters mutations in compiler generated code that checks for null by calling getClass 16:22:53 PIT >> INFO : +FKOTLIN Filters out junk mutations in bytecode created by compiler for kotlin language features 16:22:53 PIT >> INFO : +FLOGCALL Filters mutations in code that makes calls to logging frameworks 16:22:53 PIT >> INFO : +FMRNULL Filters mutations in compiler generated code that inserts Objects.requireNonNull for method references 16:22:53 PIT >> INFO : +FRETEQUIV Filters return vals mutants with bytecode equivalent to the unmutated class 16:22:53 PIT >> INFO : +FSEQUIVEQUALS Filters equivalent mutations that affect only performance in short cutting equals methods 16:22:53 PIT >> INFO : +FSTATI Filters mutations in static initializers and code called only from them 16:22:53 PIT >> INFO : +FSTATINIT Filters mutations in static initializers and code called only from them 16:22:53 PIT >> INFO : +FTRYWR Filters mutations in code generated for try with resources statements 16:22:53 PIT >> INFO : +_internal_activate_by_output_string 16:22:53 PIT >> INFO : -CLASSLIMIT Limits the maximum number of mutations per class 16:22:53 PIT >> INFO : [limit] Integer value for maximum mutations to create per class 16:22:53 PIT >> INFO : -EXPORT Exports mutants bytecode and other details to disk 16:22:53 PIT >> INFO : --------------------------------------------------------------------------- 16:22:53 PIT >> FINE : Running report with ReportOptions [targetClasses=[cn.edu.gzhu.BinaryExponentiation, cn.edu.gzhu.Date, cn.edu.gzhu.DateUtil, cn.edu.gzhu.Heap_Item, cn.edu.gzhu.DateTest, cn.edu.gzhu.Heap_ItemTest, cn.edu.gzhu.DateUtilTest, cn.edu.gzhu.BinaryExponentiationTest], excludedMethods=[], excludedClasses=[*Test], excludedTestClasses=[], codePaths=[], reportDir=E:\Eclipse\workspace\.metadata\.plugins\org.pitest.pitclipse.core\html_results, historyInputLocation=null, historyOutputLocation=null, sourceDirs=[D:\桌面\软件测试实验\实验1\Date\src, D:\桌面\软件测试实验\实验1\Date\testsrc], classPathElements=[C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839, C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.runner_2.2.1.v20230330-0839.jar, C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.runner_2.2.1.v20230330-0839.jar\target\classes, C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest.jar, C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest-entry.jar, C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest-command-line.jar, C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest-html-report.jar, C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.listeners_2.2.1.v20230330-0839.jar, C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.listeners_2.2.1.v20230330-0839.jar\target\classes, D:\桌面\软件测试实验\实验1\Date\bin, C:\Users\wj214\.p2\pool\plugins\org.junit_4.13.2.v20230809-1000.jar, C:\Users\wj214\.p2\pool\plugins\org.hamcrest_3.0.0.jar, C:\Users\wj214\.p2\pool\plugins\org.hamcrest.core_2.2.0.v20230809-1000.jar], mutators=[DEFAULTS], features=[], dependencyAnalysisMaxDistance=-1, jvmArgs=[-Djava.awt.headless=true], numberOfThreads=16, timeoutFactor=1.25, timeoutConstant=3000, targetTests=[^cn\.edu\.gzhu\.DateTest$], loggingClasses=[java.util.logging, org.apache.log4j, org.slf4j, org.apache.commons.logging, org.apache.logging.log4j], verbose=true, failWhenNoMutations=false, outputs=[HTML, PITCLIPSE_MUTATIONS, PITCLIPSE_SUMMARY], groupConfig=TestGroupConfig [excludedGroups=[], includedGroups=[]], fullMutationMatrix=false, mutationUnitSize=0, shouldCreateTimestampedReports=true, detectInlinedCode=false, exportLineCoverage=false, mutationThreshold=0, testStrengthThreshold=0, coverageThreshold=0, mutationEngine=gregor, javaExecutable=null, includeLaunchClasspath=true, properties={}, maxSurvivors=-1, excludedRunners=[], includedTestMethods=[], testPlugin=junit, useClasspathJar=false, skipFailingTests=false] 16:22:53 PIT >> FINE : System class path is C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839;C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.runner_2.2.1.v20230330-0839.jar;C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.runner_2.2.1.v20230330-0839.jar\target/classes;C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest.jar;C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest-entry.jar;C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest-command-line.jar;C:\Users\wj214\.p2\pool\plugins\org.pitest_1.6.8.v20230330-0839\lib\pitest-html-report.jar;C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.listeners_2.2.1.v20230330-0839.jar;C:\Users\wj214\.p2\pool\plugins\org.pitest.pitclipse.listeners_2.2.1.v20230330-0839.jar\target/classes;D:\桌面\软件测试实验\实验1\Date\bin;C:\Users\wj214\.p2\pool\plugins\org.junit_4.13.2.v20230809-1000.jar;C:\Users\wj214\.p2\pool\plugins\org.hamcrest_3.0.0.jar;C:\Users\wj214\.p2\pool\plugins\org.hamcrest.core_2.2.0.v20230809-1000.jar 16:22:53 PIT >> FINE : Maximum available memory is 247 mb Exception in thread "main" java.lang.IllegalArgumentException: Unsupported class file major version 66 at org.pitest.reloc.asm.ClassReader.<init>(ClassReader.java:199) at org.pitest.reloc.asm.ClassReader.<init>(ClassReader.java:180) at org.pitest.reloc.asm.ClassReader.<init>(ClassReader.java:166) at org.pitest.classinfo.ClassInfoVisitor.getClassInfo(ClassInfoVisitor.java:41) at org.pitest.classinfo.Repository.nameToClassInfo(Repository.java:70) at org.pitest.classinfo.Repository.fetchClass(Repository.java:60) at org.pitest.classinfo.NameToClassInfo.apply(NameToClassInfo.java:17) at org.pitest.classinfo.NameToClassInfo.apply(NameToClassInfo.java:7) at java.util.function.Function.lambda$andThen$1(Function.java:88) at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:267) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1380) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at org.pitest.classpath.CodeSource.getCode(CodeSource.java:44) at org.pitest.mutationtest.verify.DefaultBuildVerifier.verify(DefaultBuildVerifier.java:32) at org.pitest.mutationtest.tooling.MutationCoverage.verifyBuildSuitableForMutationTesting(MutationCoverage.java:276) at org.pitest.mutationtest.tooling.MutationCoverage.runReport(MutationCoverage.java:119) at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:125) at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:52) at org.pitest.mutationtest.commandline.MutationCoverageReport.runReport(MutationCoverageReport.java:98) at org.pitest.mutationtest.commandline.MutationCoverageReport.main(MutationCoverageReport.java:45) at org.pitest.pitclipse.runner.PitRunner.apply(PitRunner.java:35) at org.pitest.pitclipse.runner.PitRunner.apply(PitRunner.java:1) at java.util.Optional.map(Optional.java:215) at org.pitest.pitclipse.runner.PitRunnerMain.main(PitRunnerMain.java:38)
最新发布
10-18
package com.isa.navi.jni.hmi; import static java.lang.Thread.sleep; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.StatFs; import android.util.Log; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import androidx.annotation.NonNull; import com.isa.navi.jni.hmi.update.USBListener; import com.isa.navi.library.map.UpdateEnvironment; import com.isa.navi.library.map.UpdateInfoBean; import com.isa.navi.manager.CallBackManager; import com.isa.navi.manager.CarManager; import com.isa.navi.manager.base.BaseHandlerManager; import com.isa.navi.receiver.USBReceiver; import com.isa.navi.utils.GsonUtils; import com.isa.navi.utils.LogUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.InputStreamReader; import java.time.LocalDate; import java.time.Month; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; public class HmiJNIImpl extends BaseHandlerManager implements IHmiJNI { private static final String TAG = "UPDATE"; private static final int MSG_DOWNLOAD_STATUS_CHANGE = 1; private final HmiProxyJNI mHmiProxyJNI; private final Format mFormat; private static final String PASSWORD_PREFIX = "DfCs"; private static final String PASSWORD_SUFFIX = "#@"; private static final int LAST_CHARS_LENGTH = 4; private static String updateUSBpath = ""; /** * 车辆管理实例,用于管理车辆相关的功能。 */ private CarManager mCarManager; private volatile static HmiJNIImpl mInstance; private boolean is_run = false; private final Set<String> USBPathSet = Collections.synchronizedSet(new HashSet<>()); public static HmiJNIImpl getInstance() { if (mInstance == null) { synchronized (HmiJNIImpl.class) { if (mInstance == null) { mInstance = new HmiJNIImpl(); } } } return mInstance; } private HmiJNIImpl() { super(true); mHmiProxyJNI = new HmiProxyJNI(); mFormat = Format.getInstance(); mCarManager = CarManager.getInstance(); } @Override public void initialize() { super.initialize(); LogUtils.d(TAG, "initialize : "); DfCert.getInstance().getService(); CallBackManager.getInstance().registerUSBEventChangeListener(new USBListener() { @Override public void path(String mountPath) { USBPathSet.add(mountPath); LogUtils.i(TAG, "USBPathSet:" + mountPath); } }); LogUtils.i(TAG, "Path:" + mContext.getFilesDir()); // 初始化C++模块 mHmiProxyJNI.InitializeCpp(); InstanceEngine(); //decryptUtilTest(); // UpdateTest(); } // 辅助方法:记录访问被拒绝的详细原因 private void logAccessDeniedReason(File dir) { // 记录 SELinux 拒绝日志 try { Process process = Runtime.getRuntime().exec("dmesg | grep avc"); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; boolean found = false; while ((line = reader.readLine()) != null) { if (line.contains("avc: denied") && line.contains(dir.getName())) { LogUtils.e(TAG, "SELinux拒绝记录: " + line); found = true; } } if (!found) { LogUtils.i(TAG, "未找到相关的SELinux拒绝记录"); } } catch (Exception e) { LogUtils.e(TAG, "获取SELinux日志失败"+e); } // 记录文件系统权限 try { Process process = Runtime.getRuntime().exec("ls -ld " + dir.getAbsolutePath()); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { LogUtils.i(TAG, "详细权限信息: " + line); } } catch (Exception e) { LogUtils.e(TAG, "获取详细权限失败"+e); } // 记录当前应用权限 LogUtils.i(TAG, "应用权限上下文: " + getSELinuxContext()); } // 获取当前应用的 SELinux 安全上下文 private String getSELinuxContext() { try { Process process = Runtime.getRuntime().exec("id -Z"); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); return reader.readLine(); } catch (Exception e) { return "未知: " + e.getMessage(); } } // public void upDateTest(){ // Thread UpdateTest = new Thread(new Runnable(){ // @Override // public void run() { // LogUtils.i(TAG, "upDateTest start"); // startUSBDetection(); // } // }); // // UpdateTest.setName("ISA_NAVI_upDateTest"); // UpdateTest.start(); // } public void UpdateTest() { Thread UpdateTest = new Thread(new Runnable(){ @Override public void run() { LogUtils.i(TAG, "UpdateTest start!"); setUSBPath("/data/user/0/com.isa.navi/usbpath/KVM_EU_202502_T1.0_266dd24ba609476c99293f0ef7403a9f.zip"); updateMap(); } }); UpdateTest.setName("ISA_NAVI_UpdateTest"); UpdateTest.start(); } // // public void decryptUtilTest(){ // Thread UpdateTest = new Thread(new Runnable(){ // @Override // public void run() { // try { // sleep(20); // LogUtils.i(TAG, "decryptUtilTest start"); // String encryptedZipPath = "/map/KVM_EU_202502_T1.0_266dd24ba609476c99293f0ef7403a9f.zip"; // boolean isSuccess = dataVerification(encryptedZipPath); // LogUtils.i(TAG, "验签和解密结果: " + (isSuccess ? "成功" : "失败")); // } catch (Exception e) { // LogUtils.e(TAG, "测试异常: " + e.getMessage()); // } // } // }); // // UpdateTest.setName("ISA_NAVI_decryptUtilTest"); // UpdateTest.start(); // } //读取DES秘钥文本 public String readKeyFromFile(String keyDataPath) { File keyFile = new File(keyDataPath); StringBuilder keyBuilder = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(keyFile))) { String line; while ((line = reader.readLine()) != null) { // 移除行首尾空白字符(包括换行符) String trimmedLine = line.trim(); // 跳过空行和注释行(以#开头的行) if (trimmedLine.isEmpty() || trimmedLine.startsWith("#")) { continue; } keyBuilder.append(trimmedLine); } // 返回读取到的内容 return keyBuilder.toString(); } catch (IOException e) { // 处理文件读取异常 System.err.println("读取文件失败: " + e.getMessage()); e.printStackTrace(); return null; } } public boolean desDecrypt(String DesDataPath,String key){ LogUtils.i(TAG, "encryptedZipPath[encryptedZipPath]:" + DesDataPath); LogUtils.i(TAG, "key:" + key); String signPath = get_Global_m_data_address() +"sign/"; String downLoadPath = get_Global_m_data_address(); //解压加密数据 LogUtils.i(TAG, "DesDataPath[" + DesDataPath + "] -> signPath[" + signPath + "]"); if(!unzipFile(DesDataPath, signPath)) { //删除des解密中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除des解密中间文件!"); } return false; } String str = ZipUtils.getInstance().findFiles(signPath); LogUtils.i(TAG, " des文件[" + str + "]"); //解密des文件 if(!desDecryptFile(new File(str), downLoadPath, key)) { LogUtils.e(TAG, "DesdecryptFile fail!"); //删除des解密中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除Des解密中间文件!"); } return false; } //删除des解密中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除des解密中间文件!"); } LogUtils.i(TAG, "desDecryptUtil success"); return true; } private int[] getCurrentYearAndQuarter() { int[] result = new int[2]; LocalDate currentDate = LocalDate.now(); // 获取当前年份 int currentYear = currentDate.getYear(); // 获取当前月份 Month currentMonth = currentDate.getMonth(); // 根据月份确定当前季度 int currentQuarter; switch (currentMonth) { case JANUARY: case FEBRUARY: case MARCH: currentQuarter = 1; break; case APRIL: case MAY: case JUNE: currentQuarter = 2; break; case JULY: case AUGUST: case SEPTEMBER: currentQuarter = 3; break; case OCTOBER: case NOVEMBER: case DECEMBER: currentQuarter = 4; break; default: currentQuarter = 0; } result[0] = currentYear; result[1] = currentQuarter; return result; } private int[] parseMapInfo(String mapInfo) { int[] result = new int[2]; // 检查输入字符串的长度是否为6(4位年份 + 2位季度) if (mapInfo == null || mapInfo.length() != 6) { LogUtils.e(TAG, "Input string must be in the format YYYYMM where YYYY is the year and MM is the quarter as a two-digit number."); return result; } // 提取年份(前4位) String yearStr = mapInfo.substring(0, 4); result[0] = Integer.parseInt(yearStr); // 提取季度(后2位),并验证它在1到4的范围内 String quarterStr = mapInfo.substring(4, 6); int quarter = Integer.parseInt(quarterStr); if (quarter < 1 || quarter > 4) { LogUtils.e(TAG, "Quarter must be between 1 and 4."); return result; } result[1] = quarter; return result; } public void dataVersionCheck() { Thread dataVersionCheckThread = new Thread(new Runnable() { @Override public void run() { try { UpdateInfoBean bean = new UpdateInfoBean(); String localVersion = mHmiProxyJNI.getMapInfo(); if(localVersion.isEmpty()) { bean.setUpdateStatus(4); handleDownloadStatusChange(bean); LogUtils.i(TAG, "Detected no updates for a long time"); return; } int[] currentYearAndQuarter = getCurrentYearAndQuarter(); int[] localYearAndQuarter = parseMapInfo(localVersion); int yearDifference = currentYearAndQuarter[0] - localYearAndQuarter[0]; int QuarterDifference = currentYearAndQuarter[1] - localYearAndQuarter[1]; if(yearDifference * 4 + QuarterDifference > 3) { bean.setUpdateStatus(4); handleDownloadStatusChange(bean); LogUtils.i(TAG, "Detected no updates for a long time"); } } catch (Exception e) { e.printStackTrace(); } } }); // 设置线程名称 dataVersionCheckThread.setName("ISA_NAVI_dataVersionCheck"); // 启动线程 dataVersionCheckThread.start(); } public void setContext(Context context) { if(mContext == null) { mContext = context; } language.getInstance().setContext(mContext); } @Override protected void handleMessage(Message msg) { switch (msg.what) { case MSG_DOWNLOAD_STATUS_CHANGE: handleDownloadStatusChange((String) msg.obj); break; default: break; } } private List<String> JsonArrayToListExample(JSONArray jsonArray) { List<String> stringList = new ArrayList<>(); try { // 遍历JSONArray for (int i = 0; i < jsonArray.length(); i++) { // 由于我们假设JSONArray只包含字符串,所以我们可以直接getString String item = jsonArray.getString(i); // 将字符串添加到列表中 stringList.add(item); } } catch (JSONException e) { e.printStackTrace(); } return stringList; } private UpdateInfoBean jsonToUpdateInfoBean(String json) { UpdateInfoBean result = null; try { // 解析整个JSON字符串为一个JSONObject JSONObject rootObject = new JSONObject(json); // 解析mUpdateMessage对象 JSONObject mUpdateMessage = rootObject.getJSONObject("mUpdateMessage"); String country = mUpdateMessage.getString("country"); double downloadSize = mUpdateMessage.getDouble("downloadSize"); boolean isCurrentCountry = mUpdateMessage.getBoolean("isCurrentCountry"); double progress = mUpdateMessage.getDouble("progress"); double totalSize = mUpdateMessage.getDouble("totalSize"); int updateStatus = mUpdateMessage.getInt("updateStatus"); String version = mUpdateMessage.getString("version"); // 解析mUpdateNotification对象 JSONObject mUpdateNotification = rootObject.getJSONObject("mUpdateNotification"); JSONArray updateException = mUpdateNotification.getJSONArray("UpdateException"); JSONArray updateFailedList = mUpdateNotification.getJSONArray("UpdateFailedList"); boolean updateResult = mUpdateNotification.getBoolean("UpdateResult"); JSONArray updateSuccessfulList = mUpdateNotification.getJSONArray("UpdateSuccessfulList"); // 解析mapStatus int mapStatus = rootObject.getInt("mapStatus"); UpdateInfoBean.UpdateNotification temp1 = new UpdateInfoBean.UpdateNotification(updateResult,JsonArrayToListExample(updateException),JsonArrayToListExample(updateSuccessfulList),JsonArrayToListExample(updateFailedList)); UpdateInfoBean.UpdateMessage temp2 = new UpdateInfoBean.UpdateMessage(country, version, totalSize, (int) progress, isCurrentCountry); temp2.setUpdateStatus(updateStatus); temp2.setDownloadSize(downloadSize); result = new UpdateInfoBean(mapStatus, temp1, temp2); } catch (Exception e) { LogUtils.e(TAG, "JSON parsing failed:" + e.toString()); } return result; } private void handleDownloadStatusChange(String json) { UpdateInfoBean bean = jsonToUpdateInfoBean(json); LogUtils.i(TAG, "handleDownloadStatusChange : " + bean); if (bean != null) { // 仅当status=8时检查is_run,其他状态直接放行 if(bean.getUpdateStatus() != 8 || is_run) { List<UpdateInfoBean> list = new ArrayList<>(); list.add(bean); CallBackManager.getInstance().notifyUpdateStatus(list); } } } private void handleDownloadStatusChange(UpdateInfoBean bean) { LogUtils.i(TAG, "handleDownloadStatusChange : " + bean); if (bean != null) { // 仅当status=8时检查is_run,其他状态直接放行 if(bean.getUpdateStatus() != 8 || is_run) { List<UpdateInfoBean> list = new ArrayList<>(); list.add(bean); CallBackManager.getInstance().notifyUpdateStatus(list); } } else { LogUtils.e(TAG, "UpdateInfoBean is null!"); } } public void sendUpdateMessage(String json) { LogUtils.d(TAG, "sendUpdateMessage : " + json); Message message = Message.obtain(); message.what = MSG_DOWNLOAD_STATUS_CHANGE; message.obj = json; mHandler.sendMessage(message); } @Override public void updateMap() { LogUtils.d(TAG, "activeUpdateStart : "); // 检查更新过程是否已经在运行,防止重复创建线程 if(is_run) { LogUtils.i(TAG, "更新程序已经在进行"); return; }else { is_run = true; } // 创建一个新线程来执行主动更新 Thread updateMapThread = new Thread(new Runnable() { @Override public void run() { try { // 调用JNI方法开始主动更新 mHmiProxyJNI.updateMap(); LogUtils.d(TAG, "activeUpdateStart end: "); } catch (Exception e) { e.printStackTrace(); } } }); // 设置线程名称 updateMapThread.setName("ISA_NAVI_UpdateMapThread"); // 启动线程 updateMapThread.start(); } public void updateMapend() { is_run = false; } @Override public void suspendUpdate(boolean suspend) { mHmiProxyJNI.suspendUpdate(suspend); } @Override public void cancelUpdate() { mHmiProxyJNI.cancelUpdate(); } /** * 启动USB检测线程,用于检测插入的U盘并判断是否有可用的升级文件。 */ public void startUSBDetection() { LogUtils.i(TAG, "startUSBDetection START"); // setUSBPath("/data/KVM_EU_202404_T1.2.zip"); Thread USBDetectionThread = new Thread(new Runnable(){ @Override public void run() { UpdateInfoBean bean = new UpdateInfoBean(); boolean isHaveUSBData = false; //遍历检测到的U盘路径 if(USBPathSet.isEmpty()) { //未检测到U盘,触发提示弹窗 LogUtils.e(TAG, "No USB drive detected!"); bean.setUpdateStatus(2); handleDownloadStatusChange(bean); return; } int set_num = 0; for(String usbPath : USBPathSet ) { //判断U盘路径是否真实存在 set_num ++; if(USBReceiver.isMounted(usbPath)) { File usbFile = new File(usbPath); File[] listFiles = usbFile.listFiles(); if(listFiles == null) { continue; } File newfile = null; String file_str = null; for(File file : listFiles) { LogUtils.i(TAG, "file:" + file.getAbsolutePath()); //判断U盘内是否含有升级文件 if(!file.isDirectory() && mFormat.isUpgradeFileNamingFormat(file.getName())) { isHaveUSBData = true; if(newfile == null) { newfile = file; file_str = newfile.getAbsolutePath(); } else { if(Format.getInstance().oldIsNewVersion(file.getName().replaceAll("\\.\\w+$", ""), newfile.getName().replaceAll("\\.\\w+$", ""))) { newfile = file; file_str = newfile.getAbsolutePath(); } } } } //未检测到U盘指定路径下是否有数据,触发提示弹窗 if(!isHaveUSBData || newfile == null) { LogUtils.e(TAG, "The USB drive does not contain an upgrade package!"); bean.setUpdateStatus(3); handleDownloadStatusChange(bean); return; }else{ // 从文件名中提取版本号-zwx // String localDataPath = Format.getInstance().extractVersion(getCountryDbPath()); String localDataPath = Format.getInstance().extractVersionFromDbPath(getCountryDbPath());//202501_T1.0 String newDataPath = Format.getInstance().extractVersionFromDbPath(file_str);//202502_T1.0 LogUtils.i(TAG, "file name:" + newDataPath); LogUtils.i(TAG, "localDataPath:" + localDataPath); if(localDataPath.isEmpty()) { String mapinfo = getMapInfo(); if(!mapinfo.isEmpty()) { String[] newVersionParts = new String[2]; newVersionParts = Format.getInstance().parseVersion(newDataPath); String newUpdateVersion = newVersionParts[0]; // 取第一部分:202502 LogUtils.i(TAG, "newUpdateVersion:" + newUpdateVersion); String newReleasesVersion = newVersionParts[1];//取第二部分:01/02 LogUtils.i(TAG, "newReleasesVersion:" + newReleasesVersion); LogUtils.i(TAG, "localDataPath.isEmpty() newUpdateVersion: " + newUpdateVersion); LogUtils.i(TAG, "localDataPath.isEmpty() newReleasesVersion: " + newReleasesVersion); if(Integer.parseInt(newUpdateVersion) > Integer.parseInt(mapinfo) || (Integer.parseInt(newUpdateVersion) == Integer.parseInt(mapinfo) && Double.parseDouble(newReleasesVersion) > 1)) { LogUtils.i(TAG,"Trigger USB drive update!"); bean.setUpdateStatus(0); handleDownloadStatusChange(bean); //设置U盘更新路径 updateUSBpath = usbPath; setUSBPath(newfile.getAbsolutePath()); LogUtils.i(TAG, "filePath:" + newfile.getAbsolutePath()); } else { LogUtils.e(TAG, "The upgrade package version on the USB drive is less than or equal to the vehicle's version!"); bean.setUpdateStatus(1); handleDownloadStatusChange(bean); } } else { LogUtils.i(TAG,"Trigger USB drive update!"); bean.setUpdateStatus(0); handleDownloadStatusChange(bean); //设置U盘更新路径 updateUSBpath = usbPath; setUSBPath(newfile.getAbsolutePath()); LogUtils.i(TAG, "filePath:" + newfile.getAbsolutePath()); } return; } // 判断U盘内数据版本是否大于车机数据版本 if(Format.getInstance().isNewerVersion(newDataPath, localDataPath)) { LogUtils.i(TAG,"Trigger USB drive update!"); bean.setUpdateStatus(0); handleDownloadStatusChange(bean); //设置U盘更新路径 updateUSBpath = usbPath; setUSBPath(newfile.getAbsolutePath()); LogUtils.i(TAG, "filePath:" + newfile.getAbsolutePath()); } else { LogUtils.e(TAG, "The upgrade package version on the USB drive is less than or equal to the vehicle's version!"); bean.setUpdateStatus(1); handleDownloadStatusChange(bean); } return; } } else { if(set_num == USBPathSet.size()) { //未检测到U盘,触发提示弹窗 LogUtils.e(TAG, "No USB drive detected!"); bean.setUpdateStatus(2); handleDownloadStatusChange(bean); return; } } } } }); USBDetectionThread.setName("ISA_NAVI_USBDetectionThread"); USBDetectionThread.start(); } public String getMapInfo() { String result = mHmiProxyJNI.getMapInfo(); LogUtils.i(TAG,"MapInfo:" + result); return result; } public String getUpdateVersion() { String result = mHmiProxyJNI.getUpdateVersion(); LogUtils.i(TAG,"UpdateVersion:" + result); return result; } public UpdateEnvironment checkUpdateEnvironment() { String json = mHmiProxyJNI.checkUpdateEnvironment(); LogUtils.d(TAG,"checkUpdateEnvironment JSON:" + json); UpdateEnvironment result = GsonUtils.fromJson(json, UpdateEnvironment.class); if(result == null) { LogUtils.e(TAG, "GsonUtils.fromJson(json, UpdateEnvironment.class) Fail!"); return null; } if (!result.getResult()) { List<String> temp_list = new ArrayList<>(); for (int i : result.getInt_reason()) { String str = language.getInstance().getEnvironment(i); if(str != null && !str.isEmpty()) { temp_list.add(str); } } // 更新temp对象中的reason字段 result.setReason(temp_list); } LogUtils.i(TAG,"checkUpdateEnvironment :" + result); return result; } public String getUpdatePurpose() { return language.getInstance().getUpdatePurpose(); } public String getUpdateContent() { return language.getInstance().getUpdateContent(); } public String getUserManual() { return language.getInstance().getUserManual(); } public String getUpdatedContentDescription() { return language.getInstance().getUpdatedContentDescription(); } public int getEstimatedTime() { return 30; } private void InstanceEngine() { Thread InstanceEngine = new Thread(new Runnable(){ @Override public void run() { LogUtils.d("ISA_NAVI", "InstanceEngine start!"); mHmiProxyJNI.instanceEngine(); } }); InstanceEngine.setName("ISA_NAVI_InstanceEngine"); InstanceEngine.start(); } // 获取后四位字符 @NonNull private static String getLastFourChars(String mapInfo) { if (mapInfo == null || mapInfo.isEmpty()) { LogUtils.e(TAG, "mapInfo cannot be null or empty"); return "0000"; } return mapInfo.length() >= LAST_CHARS_LENGTH ? mapInfo.substring(mapInfo.length() - LAST_CHARS_LENGTH) : "0000"; } // 生成密码 @NonNull private String generatePassword() { String mapInfo = getMapInfo(); String lastFourChars = getLastFourChars(mapInfo); return PASSWORD_PREFIX + lastFourChars + PASSWORD_SUFFIX; } // 校验密码 public boolean validatePassword(String inputPassword) { if (inputPassword == null) { return false; } String generatedPassword = generatePassword(); LogUtils.i(TAG, "generatedPassword:" + generatedPassword); LogUtils.i(TAG, "inputPassword:" + inputPassword); return inputPassword.equals(generatedPassword); } public void setUSBPath(String USBPath) { mHmiProxyJNI.setUSBPath(USBPath); } public boolean unzipFile(String zipFilePath, String destinationDirPath) { return ZipUtils.getInstance().unzip(zipFilePath, destinationDirPath); } public long getFileSize(String filePath) { File file = new File(filePath); if(!file.isFile() || !file.exists()) { return 0; } LogUtils.d(TAG, "getFileSize:" + file.length()); return file.length(); } public long getAvailableSpace(String filePath) { StatFs stat = new StatFs(filePath); long availableBlocks = stat.getAvailableBlocksLong(); long blockSize = stat.getBlockSizeLong(); LogUtils.i(TAG, "[AvailableSpace]:" + availableBlocks * blockSize + "字节"); return availableBlocks * blockSize; } public String getFail(int i) { return language.getInstance().getFail(i); } public boolean decryptFile(String encryptedFilePath, String decryptedFilePath) { return new DecryptUtil().decryptFile(encryptedFilePath, decryptedFilePath, DfCert.getInstance().getKEY_AES_256()); } public boolean desDecryptFile(File desDaraPath,String downLoadPath,String key){ return new DecryptUtil().desDecryptFile(desDaraPath, downLoadPath, key); } public boolean verifySignature(String filePath, String signFilePath) { try { return DecryptUtil.verifySignature(filePath, signFilePath, DfCert.getInstance().getPUBLIC_KEY()); } catch (Exception e) { return false; } } /** * 获取高压电池电量百分比。 * * <p>此方法通过调用`mCarManager.getHVPercent`来获取高压电池的电量百分比。如果调用成功,则返回电量百分比值; * 如果调用失败或发生异常,则捕获异常并打印堆栈跟踪,最后返回`0`。</p> * * @return 一个浮点数,表示高压电池的电量百分比(0-100);如果获取失败或发生异常,则返回`0`。 */ public float getHVPercent() { float HVPercent = 0; try { HVPercent = mCarManager.getHVPercent(); if(HVPercent > 100 || HVPercent < 0) { HVPercent = 0; } } catch (Exception e) { e.printStackTrace(); } return HVPercent; } boolean isMounted() { return USBReceiver.isMounted(updateUSBpath); } public String getCountryDbPath() { return mHmiProxyJNI.getCountryDbPath(); } public String get_Global_m_data_address() { return mHmiProxyJNI.get_Global_m_data_address(); } public boolean dataVerification(String verifyDataPath) { LogUtils.i(TAG, "dataVerification[verifyDataPath]:" + verifyDataPath); String signPath = get_Global_m_data_address() + "sign/"; if(!mapControl()) { return false; } //解压加密数据 LogUtils.i(TAG, "verifyDataPath[" + verifyDataPath + "] -> signPath[" + signPath + "]"); if(!unzipFile(verifyDataPath, signPath)) { //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } return false; } if(!mapControl()) { return false; } //提取签名文件以及加密文件的绝对路径 String[] temp = ZipUtils.getInstance().findEncryptedZipFiles(signPath); String aesDaraPath = temp[1]; String signDataPtah = temp[0]; String KeyDataPath = temp [2]; LogUtils.i(TAG, "aesDaraPath:" + aesDaraPath); LogUtils.i(TAG, "signDataPtah" + signDataPtah); LogUtils.i(TAG, "KeyDataPath" + KeyDataPath); if(aesDaraPath == null || signDataPtah == null || KeyDataPath == null){ return false; } String key = readKeyFromFile(KeyDataPath); if(!mapControl()) { return false; } //验证签名 if(!verifySignature(aesDaraPath, signDataPtah)) { LogUtils.e(TAG, "verifySignature fail!"); //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } return false; } if(!mapControl()) { return false; } //对称解密Zip if(!decryptFile(aesDaraPath, verifyDataPath)) { LogUtils.e(TAG, "decryptFile fail!"); //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } return false; } //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } //des解密 LogUtils.i(TAG, "verifyDataPath:" + verifyDataPath); boolean isSuccess = desDecrypt(verifyDataPath,key); if(!isSuccess){ LogUtils.i(TAG, "DES解密结果: 失败" ); return false; } LogUtils.i(TAG, "DES解密结果:成功 " ); LogUtils.i(TAG, "dataVerification success"); return true; } /** * 删除指定目录及其所有内容 * * @param directory 指定的目录路径 * @return 如果删除成功返回 true,否则返回 false */ public boolean deleteDirectory(String directory) { File dir = new File(directory); if (!dir.exists()) { LogUtils.e("目录不存在: " + directory); return false; // 目录不存在,视为删除失败 } if (!dir.isDirectory()) { LogUtils.e("指定路径不是一个目录: " + directory); return false; // 路径不是目录,无法删除 } return deleteRecursive(dir); // 递归删除目录 } /** * 递归删除文件或目录 * * @param file 文件或目录 * @return 如果删除成功返回 true,否则返回 false */ private boolean deleteRecursive(File file) { if (file.isDirectory()) { // 如果是目录,递归删除其所有子文件和子目录 File[] files = file.listFiles(); if (files != null) { for (File subFile : files) { if (!deleteRecursive(subFile)) { return false; // 如果某个子文件或子目录删除失败,则整体失败 } } } } // 删除当前文件或空目录 if (!file.delete()) { LogUtils.e("无法删除文件或目录: " + file.getAbsolutePath()); return false; // 删除失败 } LogUtils.i("已成功删除: " + file.getAbsolutePath()); return true; // 删除成功 } public boolean mapControl() { LogUtils.d(TAG, "mapControl JAVA start"); return mHmiProxyJNI.mapControl(); } public boolean zipDbFiles(String sourceDir, String outputZipPath) { return ZipUtils.getInstance().zipDbFiles(sourceDir, outputZipPath); } public boolean zip(String sourcePath, String outputZipPath) { return ZipUtils.getInstance().zip(sourcePath, outputZipPath, true); } // Used to load the 'native-lib' library on application startup. static { LogUtils.d(TAG, "loadLibrary IsaEngineJni " + System.currentTimeMillis()); System.loadLibrary("IsaEngineJni"); } } package com.isa.navi.jni.hmi; import android.os.Build; import android.util.Base64; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.nio.charset.StandardCharsets; import java.io.*; import java.nio.charset.StandardCharsets; import android.util.Base64; import com.isa.navi.utils.LogUtils; import java.io.IOException; import java.io.ByteArrayInputStream; import java.security.PublicKey; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.List; import org.json.JSONObject; import org.json.JSONException; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.NoSuchAlgorithmException; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.MessageDigest; import java.security.Security; import java.security.Signature; import java.util.Objects; import javax.crypto.Cipher; import javax.crypto.CipherOutputStream; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * 对称解密管理类,负责提供对称解密相关方法。 */ public class DecryptUtil { /** * 用于日志记录的标签。 * <p>这是一个静态常量,用于在日志输出中标识下载管理器的相关日志。</p> */ private static final String TAG = "DecryptUtil"; private long lastCheckTime; static { Security.addProvider(new BouncyCastleProvider()); } /** * 对称解密文件 * @param encryptedFilePath 加密文件路径 * @param decryptedFilePath 解密后文件输出路径 * @param ENCRYPTION_KEY_BASE64 密钥 * @return 解密是否成功,成功返回true,失败返回false */ public boolean decryptFile(String encryptedFilePath, String decryptedFilePath, String ENCRYPTION_KEY_BASE64) { boolean success = false; try { // 创建密钥和IV规格 SecretKeySpec keySpec = new SecretKeySpec(getKey(ENCRYPTION_KEY_BASE64), "AES/CBC/PKCS5Padding"); IvParameterSpec ivSpec = new IvParameterSpec(getIV(ENCRYPTION_KEY_BASE64)); LogUtils.i(TAG, "创建密钥和IV规格 success!"); LogUtils.i(TAG, "创建密钥和IV规格 success!"); // 创建Cipher实例并初始化 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); LogUtils.i(TAG, "创建Cipher实例并初始化 success!"); if(!HmiJNIImpl.getInstance().mapControl()) { return false; } //读取文件进行对称解密,并将解密后的文件按照指定路径输出 try (FileInputStream fis = new FileInputStream(encryptedFilePath); BufferedInputStream bis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream(decryptedFilePath); CipherOutputStream cos = new CipherOutputStream(fos, cipher)) { byte[] buffer = new byte[10240]; // 使用10KB的缓冲区 int bytesRead; while ((bytesRead = bis.read(buffer)) != -1) { cos.write(buffer, 0, bytesRead); // 优化后的检查逻辑(每秒最多1次) long currentTime = System.currentTimeMillis(); if (currentTime - lastCheckTime > 1000) { synchronized (this) { if (currentTime - lastCheckTime > 1000) { if (!HmiJNIImpl.getInstance().mapControl()) { return false; } lastCheckTime = currentTime; } } } } LogUtils.i(TAG, "解密并写入数据 success!"); success = true; } catch (IOException e) { LogUtils.e(TAG, "处理文件时发生错误:" + e.getMessage()); throw new IOException("文件处理失败", e); } } catch (Exception e) { // 捕获所有其他异常并记录错误 LogUtils.e(TAG, "解密文件时发生错误:" + e.getMessage()); } return success; } /** * 验签 * @param filePath 加密文件路径 * @param signFilePath 签名文件路径(.sig文件) * @param CERT_KEY 公钥 * @return 签名成功返回true,签名失败返回false */ public static boolean verifySignature(String filePath, String signFilePath, String CERT_KEY) throws Exception { if(!HmiJNIImpl.getInstance().mapControl()) { return false; } try{ // 获取加密文件的SHA256哈希值 byte[] fileHash = getFileHash(filePath); // 读取base64格式签名数据 String base64Signature = readSignatureFromFile(signFilePath); LogUtils.i("base64格式签名数据: " + base64Signature); // 解码签名 byte[] signatureBytes = Base64.decode(base64Signature,Base64.DEFAULT); // 加载公钥 PublicKey publicKey = loadPublicKey(CERT_KEY); LogUtils.i("PUBLIC_KEY: " + publicKey); if(!HmiJNIImpl.getInstance().mapControl()) { return false; } // 验签 Signature signature = Signature.getInstance("SHA256withRSA"); signature.initVerify(publicKey); signature.update(fileHash); return signature.verify(signatureBytes); } catch (Exception e){ e.printStackTrace(); return false; } } public boolean desDecryptFile(File desDataPath, String downLoadPath, String key) { final int BUFFER_SIZE = 8 * 1024 * 1024; // 8MB缓冲区 try { // // 生成密钥(与加密时一致) // byte[] utf8Bytes = key.getBytes(StandardCharsets.UTF_8); // // // 2. Base64 编码(使用 Base64.DEFAULT,无换行) // String base64Str = Base64.encodeToString(utf8Bytes,Base64.DEFAULT); // // // 3. 取前16个字符 // String result = base64Str.substring(0, 16); // // byte[] byteStream = result.getBytes(StandardCharsets.UTF_8); // SecretKeySpec secretKeySpec = new SecretKeySpec(byteStream, "DES"); LogUtils.i(TAG,"开始解析des秘钥"); DESKeySpec desKeySpec = new DESKeySpec(Base64.encode(key.getBytes("utf-8"), Base64.DEFAULT)); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); LogUtils.i(TAG,"des秘钥解析成功"); LogUtils.i(TAG,"初始化DES秘钥"); // 初始化DES解密Cipher Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKey); LogUtils.i(TAG,"秘钥初始化完成"); LogUtils.i(TAG,"开始解析文件"); // 解析文件名 String name = desDataPath.getName(); int lastDotIndex = name.lastIndexOf("."); String fileExtension = (lastDotIndex == -1) ? "" : name.substring(lastDotIndex + 1); int firstIndex = name.indexOf("_"); String fileNameContent = (firstIndex == -1) ? name : name.substring(0, firstIndex); // 创建输出文件 File outputFile = new File(downLoadPath, fileNameContent + "." + fileExtension); try (InputStream inputStream = new FileInputStream(desDataPath); BufferedInputStream bis = new BufferedInputStream(inputStream); FileOutputStream fos = new FileOutputStream(outputFile); BufferedOutputStream bos = new BufferedOutputStream(fos)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Android 8.0+ 使用流式Base64解码 LogUtils.i("Android 8.0+ 使用流式Base64解码"); java.util.Base64.Decoder base64Decoder = java.util.Base64.getMimeDecoder(); try (InputStream base64DecodeStream = base64Decoder.wrap(bis); CipherInputStream cis = new CipherInputStream(base64DecodeStream, cipher)) { byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = cis.read(buffer)) != -1) { bos.write(buffer, 0, bytesRead); // 优化后的检查逻辑(每秒最多1次) long currentTime = System.currentTimeMillis(); if (currentTime - lastCheckTime > 1000) { synchronized (this) { if (currentTime - lastCheckTime > 1000) { if (!HmiJNIImpl.getInstance().mapControl()) { return false; } lastCheckTime = currentTime; } } } } } } } LogUtils.i("文件解密成功,保存为: " + outputFile.getAbsolutePath()); return true; } catch (Exception e) { // 修复5:添加详细错误日志 LogUtils.e(TAG, "解密失败: " + e.getMessage() + "\n文件: " + desDataPath.getAbsolutePath() + "\n密钥: " + key.substring(0, Math.min(4, key.length())) + "***"); return false; } } // 处理Base64数据块:解码->解密->写入 private void processBase64Chunk(ByteArrayOutputStream base64Buffer, Cipher cipher, BufferedOutputStream bos) throws Exception { byte[] base64Data = base64Buffer.toByteArray(); base64Buffer.reset(); byte[] decodedData = Base64.decode(base64Data, Base64.DEFAULT); byte[] decryptedData = cipher.update(decodedData); if (decryptedData != null) { bos.write(decryptedData); } } // 从 .sig 文件读取签名 public static String readSignatureFromFile(String sigFilePath) throws IOException , JSONException{ byte[] fileBytes = new byte[(int) new File(sigFilePath).length()]; try (FileInputStream fis = new FileInputStream(sigFilePath)) { fis.read(fileBytes); } String fileContent = new String(fileBytes).trim(); // 解析 JSON,提取 signature 字段 JSONObject json = new JSONObject(fileContent); return json.getString("signature"); } // 获取byte数组格式向量 private static byte[] getIV(String iv) { // 1. 清理密钥 String cleanKey = iv.replaceAll("\\?+$", ""); // 2. 提取第一个!到第二个!之间的部分 String[] parts = cleanKey.split("!"); if (parts.length < 2) { throw new IllegalArgumentException("Invalid key format"); } String prefix = parts[1]; String reversed = new StringBuilder(prefix.substring(0, 7)) .reverse() .append("!") .toString(); reversed = reversed + "abcdefg!"; return reversed.getBytes(StandardCharsets.UTF_8); } // 获取byte数组格式秘钥 private static byte[] getKey(String password) { String cleaned = password.replaceAll("[^!$a-zA-Z0-9]", ""); return cleaned.getBytes(StandardCharsets.UTF_8); } // 获取加密文件的SHA256哈希值 public static byte[] getFileHash(String filePath) throws IOException { try{ MessageDigest digest = MessageDigest.getInstance("SHA-256"); File file = new File(filePath); try (FileInputStream fis = new FileInputStream(file)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { digest.update(buffer, 0, bytesRead); } } return digest.digest(); }catch (NoSuchAlgorithmException e){ e.printStackTrace(); return null; } } // 加载验签公钥 public static PublicKey loadPublicKey(String base64PublicKey) throws Exception { base64PublicKey = base64PublicKey.replaceAll("\\s+", ""); base64PublicKey = base64PublicKey.replaceAll("[^A-Za-z0-9+/=]", ""); // 1. Base64解码 byte[] certBytes = Base64.decode(base64PublicKey,Base64.DEFAULT); // 2. 解析证书链(PKCS#7/P7B格式) CertificateFactory cf = CertificateFactory.getInstance("X.509"); ByteArrayInputStream bis = new ByteArrayInputStream(certBytes); List<X509Certificate> certChain = (List<X509Certificate>) cf.generateCertificates(bis); // 3. 提取第一个证书的公钥(通常是终端实体证书) if (certChain.isEmpty()) { throw new IllegalArgumentException("证书链为空!"); } return certChain.get(0).getPublicKey(); } } 分析这两段代码
09-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值