mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-01 14:44:27 +02:00
implement basic structure of APK signature block
This commit is contained in:
parent
2b6da361dc
commit
32a82f9527
@ -15,13 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.reandroid.archive2;
|
package com.reandroid.archive2;
|
||||||
|
|
||||||
import com.reandroid.archive2.block.CentralEntryHeader;
|
import com.reandroid.archive2.block.*;
|
||||||
import com.reandroid.archive2.block.EndRecord;
|
|
||||||
import com.reandroid.archive2.block.LocalFileHeader;
|
|
||||||
import com.reandroid.archive2.io.ArchiveFile;
|
import com.reandroid.archive2.io.ArchiveFile;
|
||||||
import com.reandroid.archive2.io.ArchiveUtil;
|
import com.reandroid.archive2.io.ArchiveUtil;
|
||||||
import com.reandroid.archive2.io.ZipSource;
|
import com.reandroid.archive2.io.ZipSource;
|
||||||
import com.reandroid.archive2.model.ApkSigBlock;
|
|
||||||
import com.reandroid.archive2.model.LocalFileDirectory;
|
import com.reandroid.archive2.model.LocalFileDirectory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -38,7 +35,7 @@ public class Archive {
|
|||||||
private final ZipSource zipSource;
|
private final ZipSource zipSource;
|
||||||
private final List<ArchiveEntry> entryList;
|
private final List<ArchiveEntry> entryList;
|
||||||
private final EndRecord endRecord;
|
private final EndRecord endRecord;
|
||||||
private final ApkSigBlock apkSigBlock;
|
private final ApkSignatureBlock apkSignatureBlock;
|
||||||
public Archive(ZipSource zipSource) throws IOException {
|
public Archive(ZipSource zipSource) throws IOException {
|
||||||
this.zipSource = zipSource;
|
this.zipSource = zipSource;
|
||||||
LocalFileDirectory lfd = new LocalFileDirectory();
|
LocalFileDirectory lfd = new LocalFileDirectory();
|
||||||
@ -54,7 +51,7 @@ public class Archive {
|
|||||||
}
|
}
|
||||||
this.entryList = entryList;
|
this.entryList = entryList;
|
||||||
this.endRecord = lfd.getCentralFileDirectory().getEndRecord();
|
this.endRecord = lfd.getCentralFileDirectory().getEndRecord();
|
||||||
this.apkSigBlock = lfd.getApkSigBlock();
|
this.apkSignatureBlock = lfd.getApkSigBlock();
|
||||||
}
|
}
|
||||||
public Archive(File file) throws IOException {
|
public Archive(File file) throws IOException {
|
||||||
this(new ArchiveFile(file));
|
this(new ArchiveFile(file));
|
||||||
@ -74,8 +71,8 @@ public class Archive {
|
|||||||
return entryList;
|
return entryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApkSigBlock getApkSigBlock() {
|
public ApkSignatureBlock getApkSigBlock() {
|
||||||
return apkSigBlock;
|
return apkSignatureBlock;
|
||||||
}
|
}
|
||||||
public EndRecord getEndRecord() {
|
public EndRecord getEndRecord() {
|
||||||
return endRecord;
|
return endRecord;
|
||||||
@ -104,4 +101,12 @@ public class Archive {
|
|||||||
String name = archiveEntry.getName().replace('/', File.separatorChar);
|
String name = archiveEntry.getName().replace('/', File.separatorChar);
|
||||||
return new File(dir, name);
|
return new File(dir, name);
|
||||||
}
|
}
|
||||||
|
// for test
|
||||||
|
public void writeSignatureData(File dir) throws IOException{
|
||||||
|
ApkSignatureBlock apkSignatureBlock = getApkSigBlock();
|
||||||
|
if(apkSignatureBlock == null){
|
||||||
|
throw new IOException("Does not have signature block");
|
||||||
|
}
|
||||||
|
apkSignatureBlock.writeSignatureData(dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2022 github.com/REAndroid
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.reandroid.archive2.block;
|
|
||||||
|
|
||||||
import com.reandroid.arsc.decoder.ValueDecoder;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class ApkSignature extends ZipBlock{
|
|
||||||
public ApkSignature() {
|
|
||||||
super(MIN_SIZE);
|
|
||||||
}
|
|
||||||
public boolean isValid(){
|
|
||||||
return getSigSize() > MIN_SIZE && getId() != null;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public int readBytes(InputStream inputStream) throws IOException {
|
|
||||||
setBytesLength(8, false);
|
|
||||||
byte[] bytes = getBytesInternal();
|
|
||||||
int read = inputStream.read(bytes, 0, bytes.length);
|
|
||||||
if(read != bytes.length){
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
int offset = bytes.length;
|
|
||||||
int length = (int) getSigSize();
|
|
||||||
setSigSize(length);
|
|
||||||
|
|
||||||
bytes = getBytesInternal();
|
|
||||||
int dataRead = inputStream.read(bytes, offset, length);
|
|
||||||
if(dataRead != length){
|
|
||||||
setSigSize(0);
|
|
||||||
}
|
|
||||||
return read + dataRead;
|
|
||||||
}
|
|
||||||
public long getSigSize(){
|
|
||||||
return getLong(OFFSET_size);
|
|
||||||
}
|
|
||||||
public void setSigSize(long size){
|
|
||||||
int length = (int) (OFFSET_id + size);
|
|
||||||
setBytesLength(length, false);
|
|
||||||
putLong(OFFSET_size, size);
|
|
||||||
}
|
|
||||||
public int getIdValue(){
|
|
||||||
return getInteger(OFFSET_id);
|
|
||||||
}
|
|
||||||
public Id getId(){
|
|
||||||
return Id.valueOf(getIdValue());
|
|
||||||
}
|
|
||||||
public void setId(int id){
|
|
||||||
putInteger(OFFSET_id, id);
|
|
||||||
}
|
|
||||||
public void setId(Id signatureId){
|
|
||||||
setId(signatureId == null? 0 : signatureId.getId());
|
|
||||||
}
|
|
||||||
public byte[] getData(){
|
|
||||||
return getBytes(OFFSET_data, (int) getSigSize() - 4, true);
|
|
||||||
}
|
|
||||||
public void setData(byte[] data){
|
|
||||||
if(data == null){
|
|
||||||
data = new byte[0];
|
|
||||||
}
|
|
||||||
setData(data, 0, data.length);
|
|
||||||
}
|
|
||||||
public void setData(byte[] data, int offset, int length){
|
|
||||||
setSigSize(length);
|
|
||||||
putBytes(data, offset, OFFSET_data, data.length);
|
|
||||||
}
|
|
||||||
public void writeData(OutputStream outputStream) throws IOException{
|
|
||||||
byte[] bytes = getBytesInternal();
|
|
||||||
outputStream.write(bytes, OFFSET_data, (int) (getSigSize() - 4));
|
|
||||||
}
|
|
||||||
public void writeData(File file) throws IOException{
|
|
||||||
File dir = file.getParentFile();
|
|
||||||
if(dir != null && !dir.exists()){
|
|
||||||
dir.mkdirs();
|
|
||||||
}
|
|
||||||
FileOutputStream outputStream = new FileOutputStream(file);
|
|
||||||
writeData(outputStream);
|
|
||||||
outputStream.close();
|
|
||||||
}
|
|
||||||
public File writeToDir(File dir) throws IOException{
|
|
||||||
File file = new File(dir, getId().toFileName());
|
|
||||||
writeData(file);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getId() + ", size=" + getSigSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class Id {
|
|
||||||
private final String name;
|
|
||||||
private final int id;
|
|
||||||
|
|
||||||
private Id(String name, int id) {
|
|
||||||
this.name = name;
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
public String name() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
public int getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
public String toFileName(){
|
|
||||||
if(this.name != null){
|
|
||||||
return name + FILE_EXTENSION;
|
|
||||||
}
|
|
||||||
return String.format("0x%08x", id) + FILE_EXTENSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null || getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Id that = (Id) obj;
|
|
||||||
return id == that.id;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
String name = this.name;
|
|
||||||
if(name != null){
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
return "UNKNOWN("+String.format("0x%08x", id)+")";
|
|
||||||
}
|
|
||||||
public static Id valueOf(String name){
|
|
||||||
if(name == null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String ext = FILE_EXTENSION;
|
|
||||||
if(name.endsWith(ext)){
|
|
||||||
name = name.substring(0, name.length()-ext.length());
|
|
||||||
}
|
|
||||||
for(Id signatureId:VALUES){
|
|
||||||
if(name.equalsIgnoreCase(signatureId.name())){
|
|
||||||
return signatureId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(ValueDecoder.isHex(name)){
|
|
||||||
return new Id(null, ValueDecoder.parseHex(name));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public static Id valueOf(int id){
|
|
||||||
if(id == 0){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for(Id signatureId:VALUES){
|
|
||||||
if(id == signatureId.getId()){
|
|
||||||
return signatureId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Id(null, id);
|
|
||||||
}
|
|
||||||
public static Id[] values() {
|
|
||||||
return VALUES.clone();
|
|
||||||
}
|
|
||||||
public static final Id V2 = new Id("V2", 0x7109871A);
|
|
||||||
public static final Id V3 = new Id("V3",0xF05368C0);
|
|
||||||
public static final Id V31 = new Id("V31",0x1B93AD61);
|
|
||||||
public static final Id STAMP_V1 = new Id("STAMP_V1", 0x2B09189E);
|
|
||||||
public static final Id STAMP_V2 = new Id("STAMP_V2", 0x6DFF800D);
|
|
||||||
public static final Id PADDING = new Id("PADDING", 0x42726577);
|
|
||||||
|
|
||||||
|
|
||||||
private static final Id[] VALUES = new Id[]{
|
|
||||||
V2, V3, V31, STAMP_V1, STAMP_V2, PADDING
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String FILE_EXTENSION = ".bin";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int MIN_SIZE = 12;
|
|
||||||
|
|
||||||
private static final int OFFSET_size = 0;
|
|
||||||
private static final int OFFSET_id = 8;
|
|
||||||
private static final int OFFSET_data = 12;
|
|
||||||
}
|
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ApkSignatureBlock extends LengthPrefixedList<SignatureInfo> {
|
||||||
|
public ApkSignatureBlock(SignatureFooter signatureFooter){
|
||||||
|
super(true);
|
||||||
|
setBottomBlock(signatureFooter);
|
||||||
|
}
|
||||||
|
public List<SignatureInfo> getSignatures(){
|
||||||
|
return super.getElements();
|
||||||
|
}
|
||||||
|
public int countSignatures(){
|
||||||
|
return super.getElementsCount();
|
||||||
|
}
|
||||||
|
public SignatureInfo getSignature(SignatureId signatureId){
|
||||||
|
for(SignatureInfo signatureInfo:getSignatures()){
|
||||||
|
if(signatureInfo.getId().equals(signatureId)){
|
||||||
|
return signatureInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public SignatureFooter getSignatureFooter(){
|
||||||
|
return (SignatureFooter) getBottomBlock();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public SignatureInfo newInstance() {
|
||||||
|
return new SignatureInfo();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onRefreshed(){
|
||||||
|
SignatureFooter footer = getSignatureFooter();
|
||||||
|
footer.updateMagic();
|
||||||
|
super.onRefreshed();
|
||||||
|
footer.setSignatureSize(getDataSize());
|
||||||
|
}
|
||||||
|
// for test
|
||||||
|
public void writeSignatureData(File dir) throws IOException{
|
||||||
|
for(SignatureInfo signatureInfo:getElements()){
|
||||||
|
signatureInfo.writeToDir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES = 1024 * 1024;
|
||||||
|
public static final int ANDROID_COMMON_PAGE_ALIGNMENT_BYTES = 4096;
|
||||||
|
|
||||||
|
private static final byte[] APK_SIGNING_BLOCK_MAGIC = new byte[] {
|
||||||
|
0x41, 0x50, 0x4b, 0x20, 0x53, 0x69, 0x67, 0x20,
|
||||||
|
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x34, 0x32,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int VERSION_SOURCE_STAMP = 0;
|
||||||
|
public static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
|
||||||
|
public static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
|
||||||
|
public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3;
|
||||||
|
public static final int VERSION_APK_SIGNATURE_SCHEME_V31 = 31;
|
||||||
|
public static final int VERSION_APK_SIGNATURE_SCHEME_V4 = 4;
|
||||||
|
|
||||||
|
}
|
36
src/main/java/com/reandroid/archive2/block/BottomBlock.java
Normal file
36
src/main/java/com/reandroid/archive2/block/BottomBlock.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import com.reandroid.arsc.container.BlockList;
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
// General purpose block to consume the remaining bytes of BlockReader
|
||||||
|
public class BottomBlock extends BlockList<LengthPrefixedBytes> {
|
||||||
|
public BottomBlock(){
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onReadBytes(BlockReader reader) throws IOException {
|
||||||
|
while (reader.isAvailable()){
|
||||||
|
LengthPrefixedBytes prefixedBytes = new LengthPrefixedBytes(false);
|
||||||
|
prefixedBytes.readBytes(reader);
|
||||||
|
this.add(prefixedBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
public class CertificateBlock extends LengthPrefixedBytes{
|
||||||
|
public CertificateBlock() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509Certificate getCertificate(){
|
||||||
|
return generateCertificate(getByteArray().toArray());
|
||||||
|
}
|
||||||
|
public static X509Certificate generateCertificate(byte[] encodedForm){
|
||||||
|
CertificateFactory factory = getCertFactory();
|
||||||
|
if(factory == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
// TODO: cert bytes could be in DER format ?
|
||||||
|
return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedForm));
|
||||||
|
}catch (CertificateException ignored){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static CertificateFactory getCertFactory() {
|
||||||
|
if (sCertFactory == null) {
|
||||||
|
try {
|
||||||
|
sCertFactory = CertificateFactory.getInstance("X.509");
|
||||||
|
} catch (CertificateException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sCertFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CertificateFactory sCertFactory = null;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
|
||||||
|
public class CertificateBlockList extends LengthPrefixedList<CertificateBlock>{
|
||||||
|
public CertificateBlockList() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public CertificateBlock newInstance() {
|
||||||
|
return new CertificateBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import com.reandroid.arsc.base.Block;
|
||||||
|
import com.reandroid.arsc.container.ExpandableBlockContainer;
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
import com.reandroid.arsc.item.IntegerItem;
|
||||||
|
import com.reandroid.arsc.item.LongItem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class LengthPrefixedBlock extends ExpandableBlockContainer{
|
||||||
|
private final Block numberBlock;
|
||||||
|
public LengthPrefixedBlock(int childesCount, boolean is_long) {
|
||||||
|
super(1 + childesCount);
|
||||||
|
Block numberBlock;
|
||||||
|
if(is_long){
|
||||||
|
numberBlock = new LongItem();
|
||||||
|
}else {
|
||||||
|
numberBlock = new IntegerItem();
|
||||||
|
}
|
||||||
|
this.numberBlock = numberBlock;
|
||||||
|
addChild(this.numberBlock);
|
||||||
|
}
|
||||||
|
public long getDataSize(){
|
||||||
|
Block numberBlock = this.numberBlock;
|
||||||
|
if(numberBlock instanceof LongItem){
|
||||||
|
return ((LongItem)numberBlock).get();
|
||||||
|
}
|
||||||
|
return ((IntegerItem)numberBlock).get();
|
||||||
|
}
|
||||||
|
public void setDataSize(long dataSize){
|
||||||
|
Block numberBlock = this.numberBlock;
|
||||||
|
if(numberBlock instanceof LongItem){
|
||||||
|
((LongItem)numberBlock).set(dataSize);
|
||||||
|
}else {
|
||||||
|
((IntegerItem)numberBlock).set((int) dataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onReadBytes(BlockReader reader) throws IOException {
|
||||||
|
if(!reader.isAvailable()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Block numberBlock = this.numberBlock;
|
||||||
|
numberBlock.readBytes(reader);
|
||||||
|
int dataSize = (int) getDataSize();
|
||||||
|
if(dataSize <= 0){
|
||||||
|
onSizeLoaded(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onSizeLoaded(dataSize);
|
||||||
|
BlockReader chunkReader = reader.create(dataSize);
|
||||||
|
Block[] childes = getChildes();
|
||||||
|
for(int i=0;i<childes.length;i++){
|
||||||
|
Block child = childes[i];
|
||||||
|
if(child == numberBlock){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
child.readBytes(chunkReader);
|
||||||
|
}
|
||||||
|
reader.offset(dataSize);
|
||||||
|
}
|
||||||
|
protected void onSizeLoaded(int dataSize){
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onRefreshed(){
|
||||||
|
int size = countBytes() - numberBlock.countBytes();
|
||||||
|
setDataSize(size);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return "size=" + numberBlock;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import com.reandroid.arsc.item.ByteArray;
|
||||||
|
|
||||||
|
public class LengthPrefixedBytes extends LengthPrefixedBlock{
|
||||||
|
private final ByteArray byteArray;
|
||||||
|
public LengthPrefixedBytes(boolean is_long) {
|
||||||
|
super(1, is_long);
|
||||||
|
this.byteArray = new ByteArray();
|
||||||
|
addChild(this.byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteArray getByteArray() {
|
||||||
|
return byteArray;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onSizeLoaded(int dataSize){
|
||||||
|
this.byteArray.setSize(dataSize);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import com.reandroid.arsc.base.Block;
|
||||||
|
import com.reandroid.arsc.base.BlockCreator;
|
||||||
|
import com.reandroid.arsc.container.BlockList;
|
||||||
|
import com.reandroid.arsc.container.FixedBlockContainer;
|
||||||
|
import com.reandroid.arsc.container.SingleBlockContainer;
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
import com.reandroid.arsc.item.IntegerItem;
|
||||||
|
import com.reandroid.arsc.item.LongItem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class LengthPrefixedList<T extends Block> extends FixedBlockContainer
|
||||||
|
implements BlockCreator<T> {
|
||||||
|
private final Block numberBlock;
|
||||||
|
private final BlockList<T> elements;
|
||||||
|
private final SingleBlockContainer<Block> bottomContainer;
|
||||||
|
public LengthPrefixedList(boolean is_long){
|
||||||
|
super(3);
|
||||||
|
Block numberBlock;
|
||||||
|
if(is_long){
|
||||||
|
numberBlock = new LongItem();
|
||||||
|
}else {
|
||||||
|
numberBlock = new IntegerItem();
|
||||||
|
}
|
||||||
|
this.numberBlock = numberBlock;
|
||||||
|
this.elements = new BlockList<>();
|
||||||
|
this.bottomContainer = new SingleBlockContainer<>();
|
||||||
|
addChild(0, this.numberBlock);
|
||||||
|
addChild(1, this.elements);
|
||||||
|
addChild(2, this.bottomContainer);
|
||||||
|
}
|
||||||
|
public long getDataSize(){
|
||||||
|
Block numberBlock = this.numberBlock;
|
||||||
|
if(numberBlock instanceof LongItem){
|
||||||
|
return ((LongItem)numberBlock).get();
|
||||||
|
}
|
||||||
|
return ((IntegerItem)numberBlock).get();
|
||||||
|
}
|
||||||
|
public void setDataSize(long dataSize){
|
||||||
|
Block numberBlock = this.numberBlock;
|
||||||
|
if(numberBlock instanceof LongItem){
|
||||||
|
((LongItem)numberBlock).set(dataSize);
|
||||||
|
}else {
|
||||||
|
((IntegerItem)numberBlock).set((int) dataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int getElementsCount(){
|
||||||
|
return getElements().size();
|
||||||
|
}
|
||||||
|
public List<T> getElements() {
|
||||||
|
return elements.getChildes();
|
||||||
|
}
|
||||||
|
public T add(T element){
|
||||||
|
this.elements.add(element);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
public boolean remove(T element){
|
||||||
|
return this.elements.remove(element);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onReadBytes(BlockReader reader) throws IOException{
|
||||||
|
if(!reader.isAvailable()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
numberBlock.readBytes(reader);
|
||||||
|
int totalSize = (int) getDataSize();
|
||||||
|
if(totalSize <= 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockReader chunkReader = reader.create(totalSize);
|
||||||
|
readElements(chunkReader);
|
||||||
|
if(chunkReader.isAvailable()){
|
||||||
|
String junk = "";
|
||||||
|
}
|
||||||
|
bottomContainer.readBytes(chunkReader);
|
||||||
|
reader.offset(totalSize);
|
||||||
|
}
|
||||||
|
private void readElements(BlockReader reader) throws IOException{
|
||||||
|
int preserve = bottomContainer.countBytes() + 4;
|
||||||
|
while (reader.available() > preserve){
|
||||||
|
int position = reader.getPosition();
|
||||||
|
T element = newInstance();
|
||||||
|
element = add(element);
|
||||||
|
element.readBytes(reader);
|
||||||
|
if(position == reader.getPosition()){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onRefreshed(){
|
||||||
|
int size = countBytes() - numberBlock.countBytes();
|
||||||
|
setDataSize(size);
|
||||||
|
}
|
||||||
|
public Block getBottomBlock(){
|
||||||
|
return bottomContainer.getItem();
|
||||||
|
}
|
||||||
|
public void setBottomBlock(Block block){
|
||||||
|
bottomContainer.setItem(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return "size=" + numberBlock + ", count=" + getElementsCount();
|
||||||
|
}
|
||||||
|
}
|
@ -31,25 +31,37 @@ public class SignatureFooter extends ZipBlock{
|
|||||||
byte[] bytes = getBytesInternal();
|
byte[] bytes = getBytesInternal();
|
||||||
return inputStream.read(bytes, 0, bytes.length);
|
return inputStream.read(bytes, 0, bytes.length);
|
||||||
}
|
}
|
||||||
public long getSigBlockSizeInFooter(){
|
public long getSignatureSize(){
|
||||||
return getLong(OFFSET_size);
|
return getLong(OFFSET_size);
|
||||||
}
|
}
|
||||||
public void setSigBlockSizeInFooter(long size){
|
public void setSignatureSize(long size){
|
||||||
|
int minLength = MIN_SIZE;
|
||||||
|
if(countBytes() < minLength){
|
||||||
|
setBytesLength(minLength, false);
|
||||||
|
}
|
||||||
putLong(OFFSET_size, size);
|
putLong(OFFSET_size, size);
|
||||||
}
|
}
|
||||||
public byte[] getMagic() {
|
public byte[] getMagic() {
|
||||||
return getBytes(OFFSET_magic, APK_SIG_BLOCK_MAGIC.length, false);
|
return getBytes(OFFSET_magic, APK_SIG_BLOCK_MAGIC.length, false);
|
||||||
}
|
}
|
||||||
public void setMagic(byte[] magic){
|
public void setMagic(byte[] magic){
|
||||||
|
if(magic == null){
|
||||||
|
magic = new byte[0];
|
||||||
|
}
|
||||||
|
int length = OFFSET_magic + magic.length;
|
||||||
|
setBytesLength(length, false);
|
||||||
putBytes(magic, 0, OFFSET_magic, magic.length);
|
putBytes(magic, 0, OFFSET_magic, magic.length);
|
||||||
}
|
}
|
||||||
public boolean isValid(){
|
public boolean isValid(){
|
||||||
return getSigBlockSizeInFooter() > MIN_SIZE
|
return getSignatureSize() > MIN_SIZE
|
||||||
&& ByteArray.equals(APK_SIG_BLOCK_MAGIC, getMagic());
|
&& ByteArray.equals(APK_SIG_BLOCK_MAGIC, getMagic());
|
||||||
}
|
}
|
||||||
|
public void updateMagic(){
|
||||||
|
setMagic(APK_SIG_BLOCK_MAGIC);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
return getSigBlockSizeInFooter() + " ["+new String(getMagic())+"]";
|
return getSignatureSize() + " ["+new String(getMagic())+"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int MIN_SIZE = 24;
|
public static final int MIN_SIZE = 24;
|
||||||
|
109
src/main/java/com/reandroid/archive2/block/SignatureId.java
Normal file
109
src/main/java/com/reandroid/archive2/block/SignatureId.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import com.reandroid.arsc.decoder.ValueDecoder;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class SignatureId {
|
||||||
|
private final String name;
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
private SignatureId(String name, int id) {
|
||||||
|
this.name = name;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public String name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public String toFileName() {
|
||||||
|
if (this.name != null) {
|
||||||
|
return name + FILE_EXTENSION;
|
||||||
|
}
|
||||||
|
return String.format("0x%08x", id) + FILE_EXTENSION;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SignatureId that = (SignatureId) obj;
|
||||||
|
return id == that.id;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String name = this.name;
|
||||||
|
if (name != null) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return "UNKNOWN(" + String.format("0x%08x", id) + ")";
|
||||||
|
}
|
||||||
|
public static SignatureId valueOf(String name) {
|
||||||
|
if (name == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String ext = FILE_EXTENSION;
|
||||||
|
if (name.endsWith(ext)) {
|
||||||
|
name = name.substring(0, name.length() - ext.length());
|
||||||
|
}
|
||||||
|
for (SignatureId signatureId : VALUES) {
|
||||||
|
if (name.equalsIgnoreCase(signatureId.name())) {
|
||||||
|
return signatureId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ValueDecoder.isHex(name)) {
|
||||||
|
return new SignatureId(null, ValueDecoder.parseHex(name));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static SignatureId valueOf(int id) {
|
||||||
|
for (SignatureId signatureId : VALUES) {
|
||||||
|
if (id == signatureId.getId()) {
|
||||||
|
return signatureId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new SignatureId(null, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SignatureId[] values() {
|
||||||
|
return VALUES.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final SignatureId V2 = new SignatureId("V2", 0x7109871A);
|
||||||
|
public static final SignatureId V3 = new SignatureId("V3", 0xF05368C0);
|
||||||
|
public static final SignatureId V31 = new SignatureId("V31", 0x1B93AD61);
|
||||||
|
public static final SignatureId STAMP_V1 = new SignatureId("STAMP_V1", 0x2B09189E);
|
||||||
|
public static final SignatureId STAMP_V2 = new SignatureId("STAMP_V2", 0x6DFF800D);
|
||||||
|
public static final SignatureId PADDING = new SignatureId("PADDING", 0x42726577);
|
||||||
|
public static final SignatureId NULL = new SignatureId("NULL", 0x0);
|
||||||
|
|
||||||
|
private static final SignatureId[] VALUES = new SignatureId[]{
|
||||||
|
V2, V3, V31, STAMP_V1, STAMP_V2, PADDING, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String FILE_EXTENSION = ".bin";
|
||||||
|
}
|
111
src/main/java/com/reandroid/archive2/block/SignatureInfo.java
Normal file
111
src/main/java/com/reandroid/archive2/block/SignatureInfo.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.pad.SchemePadding;
|
||||||
|
import com.reandroid.archive2.block.stamp.SchemeStampV1;
|
||||||
|
import com.reandroid.archive2.block.stamp.SchemeStampV2;
|
||||||
|
import com.reandroid.archive2.block.v2.SchemeV2;
|
||||||
|
import com.reandroid.archive2.block.v3.SchemeV3;
|
||||||
|
import com.reandroid.archive2.block.v3.SchemeV31;
|
||||||
|
import com.reandroid.arsc.base.Block;
|
||||||
|
import com.reandroid.arsc.container.SingleBlockContainer;
|
||||||
|
import com.reandroid.arsc.io.BlockLoad;
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
import com.reandroid.arsc.item.IntegerItem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SignatureInfo extends LengthPrefixedBlock implements BlockLoad {
|
||||||
|
private final IntegerItem idItem;
|
||||||
|
private final SingleBlockContainer<SignatureScheme> schemeContainer;
|
||||||
|
public SignatureInfo() {
|
||||||
|
super(2, true);
|
||||||
|
this.idItem = new IntegerItem();
|
||||||
|
this.schemeContainer = new SingleBlockContainer<>();
|
||||||
|
addChild(this.idItem);
|
||||||
|
addChild(this.schemeContainer);
|
||||||
|
this.idItem.setBlockLoad(this);
|
||||||
|
}
|
||||||
|
public int getIdValue(){
|
||||||
|
return idItem.get();
|
||||||
|
}
|
||||||
|
public SignatureId getId(){
|
||||||
|
return SignatureId.valueOf(getIdValue());
|
||||||
|
}
|
||||||
|
public void setId(int id){
|
||||||
|
idItem.set(id);
|
||||||
|
}
|
||||||
|
public void setId(SignatureId signatureId){
|
||||||
|
setId(signatureId == null? 0 : signatureId.getId());
|
||||||
|
}
|
||||||
|
public SignatureScheme getSignatureScheme(){
|
||||||
|
return schemeContainer.getItem();
|
||||||
|
}
|
||||||
|
public void setSignatureScheme(SignatureScheme signatureScheme){
|
||||||
|
schemeContainer.setItem(signatureScheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
|
||||||
|
if(sender == this.idItem){
|
||||||
|
onIdLoaded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void onIdLoaded(){
|
||||||
|
SignatureId signatureId = getId();
|
||||||
|
SignatureScheme scheme;
|
||||||
|
if(signatureId == SignatureId.V2){
|
||||||
|
scheme = new SchemeV2();
|
||||||
|
}else if(signatureId == SignatureId.V3){
|
||||||
|
scheme = new SchemeV3();
|
||||||
|
}else if(signatureId == SignatureId.V31){
|
||||||
|
scheme = new SchemeV31();
|
||||||
|
}else if(signatureId == SignatureId.STAMP_V1){
|
||||||
|
scheme = new SchemeStampV1();
|
||||||
|
}else if(signatureId == SignatureId.STAMP_V2){
|
||||||
|
scheme = new SchemeStampV2();
|
||||||
|
}else if(signatureId == SignatureId.PADDING){
|
||||||
|
scheme = new SchemePadding();
|
||||||
|
}else {
|
||||||
|
scheme = new UnknownScheme(signatureId);
|
||||||
|
}
|
||||||
|
schemeContainer.setItem(scheme);
|
||||||
|
}
|
||||||
|
// for test
|
||||||
|
public void writeData(File file) throws IOException{
|
||||||
|
File dir = file.getParentFile();
|
||||||
|
if(dir != null && !dir.exists()){
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
writeBytes(outputStream);
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
// for test
|
||||||
|
public File writeToDir(File dir) throws IOException{
|
||||||
|
File file = new File(dir, getId().toFileName());
|
||||||
|
writeData(file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getId() + ", scheme: " + getSignatureScheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block;
|
||||||
|
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
import com.reandroid.arsc.item.ByteArray;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
// General purpose block to consume the specified bytes of BlockReader
|
||||||
|
// TODO: No class should override this, implement all like SchemeV2
|
||||||
|
public class UnknownScheme extends SignatureScheme{
|
||||||
|
private final ByteArray byteArray;
|
||||||
|
public UnknownScheme(SignatureId signatureId) {
|
||||||
|
super(1, signatureId);
|
||||||
|
this.byteArray = new ByteArray();
|
||||||
|
addChild(byteArray);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onReadBytes(BlockReader reader) throws IOException {
|
||||||
|
SignatureInfo signatureInfo = getSignatureInfo();
|
||||||
|
int size = (int) signatureInfo.getDataSize() - 4;
|
||||||
|
byteArray.setSize(size);
|
||||||
|
super.onReadBytes(reader);
|
||||||
|
}
|
||||||
|
}
|
@ -98,29 +98,4 @@ public abstract class ZipBlock extends BlockItem {
|
|||||||
putShort(getBytesInternal(), offset, (short) value);
|
putShort(getBytesInternal(), offset, (short) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getLong(byte[] bytes, int offset){
|
|
||||||
if((offset + 8)>bytes.length){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
long result = 0;
|
|
||||||
int index = offset + 7;
|
|
||||||
while (index>=offset){
|
|
||||||
result = result << 8;
|
|
||||||
result |= (bytes[index] & 0xff);
|
|
||||||
index --;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
public static void putLong(byte[] bytes, int offset, long value){
|
|
||||||
if((offset + 8) > bytes.length){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int index = offset;
|
|
||||||
offset = index + 8;
|
|
||||||
while (index<offset){
|
|
||||||
bytes[index] = (byte) (value & 0xff);
|
|
||||||
value = value >>> 8;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.pad;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.SignatureId;
|
||||||
|
import com.reandroid.archive2.block.SignatureInfo;
|
||||||
|
import com.reandroid.archive2.block.SignatureScheme;
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
import com.reandroid.arsc.item.ByteArray;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SchemePadding extends SignatureScheme {
|
||||||
|
private final ByteArray byteArray;
|
||||||
|
public SchemePadding() {
|
||||||
|
super(1, SignatureId.PADDING);
|
||||||
|
this.byteArray = new ByteArray();
|
||||||
|
addChild(this.byteArray);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onReadBytes(BlockReader reader) throws IOException{
|
||||||
|
SignatureInfo signatureInfo = getSignatureInfo();
|
||||||
|
int size = (int) signatureInfo.getDataSize() - 4;
|
||||||
|
byteArray.setSize(size);
|
||||||
|
super.onReadBytes(reader);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.stamp;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.SignatureId;
|
||||||
|
import com.reandroid.archive2.block.UnknownScheme;
|
||||||
|
|
||||||
|
// TODO: implement structure
|
||||||
|
public class SchemeStampV1 extends UnknownScheme {
|
||||||
|
public SchemeStampV1() {
|
||||||
|
super(SignatureId.STAMP_V1);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.stamp;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.SignatureId;
|
||||||
|
import com.reandroid.archive2.block.UnknownScheme;
|
||||||
|
|
||||||
|
// TODO: implement structure
|
||||||
|
public class SchemeStampV2 extends UnknownScheme {
|
||||||
|
public SchemeStampV2() {
|
||||||
|
super(SignatureId.STAMP_V2);
|
||||||
|
}
|
||||||
|
}
|
29
src/main/java/com/reandroid/archive2/block/v2/SchemeV2.java
Normal file
29
src/main/java/com/reandroid/archive2/block/v2/SchemeV2.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.v2;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.SignatureId;
|
||||||
|
import com.reandroid.archive2.block.SignatureScheme;
|
||||||
|
|
||||||
|
public class SchemeV2 extends SignatureScheme {
|
||||||
|
private final V2SignedDataList signedDataList;
|
||||||
|
public SchemeV2(){
|
||||||
|
super(1, SignatureId.V2);
|
||||||
|
this.signedDataList = new V2SignedDataList();
|
||||||
|
addChild(this.signedDataList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.v2;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.LengthPrefixedBytes;
|
||||||
|
|
||||||
|
public class V2Signature extends LengthPrefixedBytes {
|
||||||
|
public V2Signature() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.v2;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.BottomBlock;
|
||||||
|
import com.reandroid.archive2.block.LengthPrefixedBlock;
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class V2SignedData extends LengthPrefixedBlock {
|
||||||
|
private final V2Signer signer;
|
||||||
|
private final BottomBlock unknown;
|
||||||
|
public V2SignedData() {
|
||||||
|
super(2, false);
|
||||||
|
this.signer = new V2Signer();
|
||||||
|
this.unknown = new BottomBlock();
|
||||||
|
addChild(this.signer);
|
||||||
|
addChild(this.unknown);
|
||||||
|
}
|
||||||
|
public void onReadBytes(BlockReader reader) throws IOException {
|
||||||
|
super.onReadBytes(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.v2;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.LengthPrefixedList;
|
||||||
|
|
||||||
|
public class V2SignedDataList extends LengthPrefixedList<V2SignedData> {
|
||||||
|
public V2SignedDataList() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V2SignedData newInstance() {
|
||||||
|
return new V2SignedData();
|
||||||
|
}
|
||||||
|
}
|
51
src/main/java/com/reandroid/archive2/block/v2/V2Signer.java
Normal file
51
src/main/java/com/reandroid/archive2/block/v2/V2Signer.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.v2;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.BottomBlock;
|
||||||
|
import com.reandroid.archive2.block.CertificateBlock;
|
||||||
|
import com.reandroid.archive2.block.CertificateBlockList;
|
||||||
|
import com.reandroid.archive2.block.LengthPrefixedBlock;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class V2Signer extends LengthPrefixedBlock {
|
||||||
|
private final V2Signature v2Signature;
|
||||||
|
private final CertificateBlockList certificateBlockList;
|
||||||
|
private final BottomBlock unknown;
|
||||||
|
public V2Signer() {
|
||||||
|
super(3, false);
|
||||||
|
this.v2Signature = new V2Signature();
|
||||||
|
this.certificateBlockList = new CertificateBlockList();
|
||||||
|
this.unknown = new BottomBlock();
|
||||||
|
addChild(this.v2Signature);
|
||||||
|
addChild(this.certificateBlockList);
|
||||||
|
addChild(this.unknown);
|
||||||
|
}
|
||||||
|
public List<CertificateBlock> getCertificateBlockList(){
|
||||||
|
return certificateBlockList.getElements();
|
||||||
|
}
|
||||||
|
public void addCertificateBlock(CertificateBlock certificateBlock){
|
||||||
|
certificateBlockList.add(certificateBlock);
|
||||||
|
}
|
||||||
|
public void removeCertificateBlock(CertificateBlock certificateBlock){
|
||||||
|
certificateBlockList.remove(certificateBlock);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return super.toString()+", sig="+v2Signature+", certs="+certificateBlockList;
|
||||||
|
}
|
||||||
|
}
|
26
src/main/java/com/reandroid/archive2/block/v3/SchemeV3.java
Normal file
26
src/main/java/com/reandroid/archive2/block/v3/SchemeV3.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.v3;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.SignatureId;
|
||||||
|
import com.reandroid.archive2.block.UnknownScheme;
|
||||||
|
|
||||||
|
// TODO: implement structure
|
||||||
|
public class SchemeV3 extends UnknownScheme {
|
||||||
|
public SchemeV3() {
|
||||||
|
super(SignatureId.V3);
|
||||||
|
}
|
||||||
|
}
|
26
src/main/java/com/reandroid/archive2/block/v3/SchemeV31.java
Normal file
26
src/main/java/com/reandroid/archive2/block/v3/SchemeV31.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.archive2.block.v3;
|
||||||
|
|
||||||
|
import com.reandroid.archive2.block.SignatureId;
|
||||||
|
import com.reandroid.archive2.block.UnknownScheme;
|
||||||
|
|
||||||
|
// TODO: implement structure
|
||||||
|
public class SchemeV31 extends UnknownScheme {
|
||||||
|
public SchemeV31() {
|
||||||
|
super(SignatureId.V31);
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2022 github.com/REAndroid
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.reandroid.archive2.model;
|
|
||||||
|
|
||||||
import com.reandroid.archive2.block.ApkSignature;
|
|
||||||
import com.reandroid.archive2.block.LongBlock;
|
|
||||||
import com.reandroid.archive2.block.SignatureFooter;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ApkSigBlock {
|
|
||||||
private final SignatureFooter signatureFooter;
|
|
||||||
private final LongBlock mSize;
|
|
||||||
private final List<ApkSignature> mSignatures;
|
|
||||||
public ApkSigBlock(SignatureFooter signatureFooter){
|
|
||||||
this.signatureFooter = signatureFooter;
|
|
||||||
this.mSize = new LongBlock();
|
|
||||||
this.mSignatures = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LongBlock getTotalSize(){
|
|
||||||
return mSize;
|
|
||||||
}
|
|
||||||
public List<ApkSignature> getSignatures() {
|
|
||||||
return mSignatures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readBytes(InputStream inputStream) throws IOException {
|
|
||||||
mSize.readBytes(inputStream);
|
|
||||||
ApkSignature apkSignature;
|
|
||||||
while ((apkSignature = readNext(inputStream))!=null){
|
|
||||||
mSignatures.add(apkSignature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private ApkSignature readNext(InputStream inputStream) throws IOException {
|
|
||||||
ApkSignature apkSignature = new ApkSignature();
|
|
||||||
apkSignature.readBytes(inputStream);
|
|
||||||
if(apkSignature.isValid()){
|
|
||||||
return apkSignature;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public void writeSigData(File dir) throws IOException{
|
|
||||||
for(ApkSignature apkSignature:mSignatures){
|
|
||||||
apkSignature.writeToDir(dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
return "size=" + getTotalSize() + ", count=" + getSignatures().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final long CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES = 1024 * 1024;
|
|
||||||
public static final int ANDROID_COMMON_PAGE_ALIGNMENT_BYTES = 4096;
|
|
||||||
|
|
||||||
private static final byte[] APK_SIGNING_BLOCK_MAGIC = new byte[] {
|
|
||||||
0x41, 0x50, 0x4b, 0x20, 0x53, 0x69, 0x67, 0x20,
|
|
||||||
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x34, 0x32,
|
|
||||||
};
|
|
||||||
public static final int VERITY_PADDING_BLOCK_ID = 0x42726577;
|
|
||||||
|
|
||||||
public static final int VERSION_SOURCE_STAMP = 0;
|
|
||||||
public static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
|
|
||||||
public static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
|
|
||||||
public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3;
|
|
||||||
public static final int VERSION_APK_SIGNATURE_SCHEME_V31 = 31;
|
|
||||||
public static final int VERSION_APK_SIGNATURE_SCHEME_V4 = 4;
|
|
||||||
|
|
||||||
}
|
|
@ -16,7 +16,9 @@
|
|||||||
package com.reandroid.archive2.model;
|
package com.reandroid.archive2.model;
|
||||||
|
|
||||||
import com.reandroid.archive2.block.*;
|
import com.reandroid.archive2.block.*;
|
||||||
|
import com.reandroid.archive2.block.ApkSignatureBlock;
|
||||||
import com.reandroid.archive2.io.ZipSource;
|
import com.reandroid.archive2.io.ZipSource;
|
||||||
|
import com.reandroid.arsc.io.BlockReader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -26,7 +28,7 @@ import java.util.List;
|
|||||||
public class LocalFileDirectory {
|
public class LocalFileDirectory {
|
||||||
private final CentralFileDirectory centralFileDirectory;
|
private final CentralFileDirectory centralFileDirectory;
|
||||||
private final List<LocalFileHeader> headerList;
|
private final List<LocalFileHeader> headerList;
|
||||||
private ApkSigBlock apkSigBlock;
|
private ApkSignatureBlock apkSignatureBlock;
|
||||||
private long mTotalDataLength;
|
private long mTotalDataLength;
|
||||||
public LocalFileDirectory(CentralFileDirectory centralFileDirectory){
|
public LocalFileDirectory(CentralFileDirectory centralFileDirectory){
|
||||||
this.centralFileDirectory = centralFileDirectory;
|
this.centralFileDirectory = centralFileDirectory;
|
||||||
@ -86,15 +88,14 @@ public class LocalFileDirectory {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EndRecord endRecord = cfd.getEndRecord();
|
EndRecord endRecord = cfd.getEndRecord();
|
||||||
long length = footer.getSigBlockSizeInFooter() + 8;
|
long length = footer.getSignatureSize() + 8;
|
||||||
long offset = endRecord.getOffsetOfCentralDirectory()
|
long offset = endRecord.getOffsetOfCentralDirectory() - length;
|
||||||
- length;
|
ApkSignatureBlock apkSignatureBlock = new ApkSignatureBlock(footer);
|
||||||
ApkSigBlock apkSigBlock = new ApkSigBlock(footer);
|
apkSignatureBlock.readBytes(new BlockReader(zipSource.getInputStream(offset, length)));
|
||||||
apkSigBlock.readBytes(zipSource.getInputStream(offset, length));
|
this.apkSignatureBlock = apkSignatureBlock;
|
||||||
this.apkSigBlock = apkSigBlock;
|
|
||||||
}
|
}
|
||||||
public ApkSigBlock getApkSigBlock() {
|
public ApkSignatureBlock getApkSigBlock() {
|
||||||
return apkSigBlock;
|
return apkSignatureBlock;
|
||||||
}
|
}
|
||||||
public CentralFileDirectory getCentralFileDirectory() {
|
public CentralFileDirectory getCentralFileDirectory() {
|
||||||
return centralFileDirectory;
|
return centralFileDirectory;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user