Java 将修改后的清单文件转换回JarEntry
在工作中,我们使用了很多已经签名的第三方库。其中一些已不再维护,但我们仍需要使用它们。由于最近的Java安全更新,这些JAR中的清单文件需要更新以包含额外的安全属性。考虑到jar文件的工作方式,我需要对每个jar执行解包编辑重新打包过程 这涉及到解包jar,向清单中添加额外属性,同时删除已经存在的SHA1签名字符串,使用我们自己的签名重新打包和调整jar。以下是我到目前为止用来解包jar的代码:Java 将修改后的清单文件转换回JarEntry,java,maven,jar,manifest.mf,Java,Maven,Jar,Manifest.mf,在工作中,我们使用了很多已经签名的第三方库。其中一些已不再维护,但我们仍需要使用它们。由于最近的Java安全更新,这些JAR中的清单文件需要更新以包含额外的安全属性。考虑到jar文件的工作方式,我需要对每个jar执行解包编辑重新打包过程 这涉及到解包jar,向清单中添加额外属性,同时删除已经存在的SHA1签名字符串,使用我们自己的签名重新打包和调整jar。以下是我到目前为止用来解包jar的代码: public static void unpackJarFile(File srcJarFile)
public static void unpackJarFile(File srcJarFile) throws IOException{
File tmpJarFile = File.createTempFile("tempJar", ".tmp");
JarFile jarFile = new JarFile(srcJarFile);
JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(tmpJarFile));
//Copy original jar file to the temporary one.
Enumeration<JarEntry> jarEntries = jarFile.entries();
while(jarEntries.hasMoreElements()) {
JarEntry temp = jarEntries.nextElement();
//if file is manifest then unsign else carry on
JarEntry entry = isManifestFile(temp) ? unsignManifest(temp, jarFile) : temp;
// ingore files ending in .SF and .RSA
if (fileIsNotSignature(entry)){
InputStream entryInputStream = jarFile.getInputStream(entry);
tempJarOutputStream.putNextEntry(entry);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = entryInputStream.read(buffer)) != -1) {
tempJarOutputStream.write(buffer, 0, bytesRead);
}
}
}
tempJarOutputStream.close();
jarFile.close();
srcJarFile.delete();
tmpJarFile.renameTo(srcJarFile);
}
private static JarEntry unsignManifest(JarEntry signed, JarFile jarFile) throws IOException {
//extract signed manifest contents into a temp text file
File tmpManifestFile = File.createTempFile("tempManifest", ".tmp");
tmpManifestFile.deleteOnExit();
Manifest manifest = jarFile.getManifest();
OutputStream fos = new FileOutputStream(tmpManifestFile);
//write out manifest contents to an actual file on disk for later editing
manifest.write(fos);
fos.close();
//read the physical file back in line by line so that SHA1 strings
//can be ignored when creating a new manifest file.
Path path = Paths.get(tmpManifestFile.getPath());
List<String> lines = Files.readAllLines(path, Charset.defaultCharset());
// some logic here. Something like
// for each line : lines
// if !line.contains("SHA1-Digest: SWDa1ic/T+le1N+UvrAYf89lY4E=")
// write it out to the new manifest file
// append extra security attributes
//convert new manifest file to new JarEntry unsigned
// return JarEntry
return unsigned;
}
publicstaticvoidunpackjarfile(文件srcJarFile)引发IOException{
File tmpJarFile=File.createTempFile(“tempJar”,“.tmp”);
JarFile JarFile=新的JarFile(srcJarFile);
JarOutputStream tempJarOutputStream=newjaroutputstream(newfileoutputstream(tmpJarFile));
//将原始jar文件复制到临时jar文件。
枚举jarEntries=jarFile.entries();
while(jarEntries.hasMoreElements()){
JarEntry temp=jarEntries.nextElement();
//如果文件是清单,则不签名,否则继续
JarEntry entry=isManifestFile(temp)?unsignManifest(temp,jarFile):temp;
//以.SF和.RSA结尾的ingore文件
如果(文件不是签名(条目)){
InputStream entryInputStream=jarFile.getInputStream(条目);
tempJarOutputStream.putNextEntry(条目);
字节[]缓冲区=新字节[1024];
int字节读取=0;
而((bytesRead=entryInputStream.read(缓冲区))!=-1){
写入(缓冲区,0,字节读取);
}
}
}
tempJarOutputStream.close();
jarFile.close();
srcJarFile.delete();
tmpJarFile.renameTo(srcJarFile);
}
私有静态JarEntry unsignManifest(JarEntry已签名,JarFile JarFile)引发IOException{
//将签名清单内容提取到临时文本文件中
File tmpManifestFile=File.createTempFile(“tempManifest”、“.tmp”);
tmpManifestFile.deleteOnExit();
Manifest Manifest=jarFile.getManifest();
OutputStream fos=新文件OutputStream(tmpManifestFile);
//将清单内容写入磁盘上的实际文件,以便以后编辑
舱单写入(fos);
fos.close();
//逐行读取物理文件,使SHA1字符串
//创建新清单文件时可以忽略。
Path Path=Path.get(tmpManifestFile.getPath());
列表行=Files.readAllLines(路径,Charset.defaultCharset());
//这里有些逻辑,比如
//每行:行
//if!line.contains(“SHA1摘要:SWDa1ic/T+le1N+UvrAYf89lY4E=”)
//将其写入新的清单文件
//附加额外的安全属性
//将新清单文件转换为未签名的新条目
//返回项
未签名返回;
}
考虑到Java的JarEntry和Manifest类的单向性,看起来我必须完成所有繁重的工作。我可以把这些值拿出来,但在我看来,选择性地把它们放进去是痛苦的。到目前为止,我可以打开包装并重新包装罐子。正如您在代码末尾所看到的,我只是不知道如何有选择地将内容放回清单文件并将其转换为JarEntry,以便unpackJarFile()方法认为新创建的清单文件来自原始jar
提前谢谢