• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package com.ohos.hapsigntool.codesigning.datastructure;
17 
18 import com.ohos.hapsigntool.codesigning.exception.VerifyCodeSignException;
19 
20 import java.nio.ByteBuffer;
21 import java.nio.ByteOrder;
22 import java.util.Arrays;
23 import java.util.Locale;
24 
25 /**
26  * Merkle tree extension is a type of Extension to store a merkle tree's information, i.e. size and root hash, ect.
27  * <p>
28  * structure
29  * <p>
30  * 1) u32 type
31  * <p>
32  * 2) u64 merkleTreeSize: the size of merkle tree
33  * <p>
34  * 3) u64 merkleTreeOffset: offset of the merkle tree by the start of the file.
35  * <p>
36  * 4) u8[64] rootHash: merkle tree root hash
37  *
38  * @since 2023/09/08
39  */
40 public class MerkleTreeExtension extends Extension {
41     /**
42      * Type of MerkleTreeExtension
43      */
44     public static final int MERKLE_TREE_INLINED = 0x1;
45 
46     /**
47      * Byte size of MerkleTreeExtension including merkleTreeSize, offset and root hash.
48      */
49     public static final int MERKLE_TREE_EXTENSION_DATA_SIZE = 80;
50 
51     private static final int ROOT_HASH_SIZE = 64;
52 
53     private final long merkleTreeSize;
54 
55     private long merkleTreeOffset;
56 
57     private byte[] rootHash;
58 
59     /**
60      * Constructor for MerkleTreeExtension
61      *
62      * @param merkleTreeSize   Byte array representation of merkle tree
63      * @param merkleTreeOffset merkle tree offset based on file start
64      * @param rootHash         Root hash of the merkle tree
65      */
MerkleTreeExtension(long merkleTreeSize, long merkleTreeOffset, byte[] rootHash)66     public MerkleTreeExtension(long merkleTreeSize, long merkleTreeOffset, byte[] rootHash) {
67         super(MERKLE_TREE_INLINED, MERKLE_TREE_EXTENSION_DATA_SIZE);
68         this.merkleTreeSize = merkleTreeSize;
69         this.merkleTreeOffset = merkleTreeOffset;
70         if (rootHash == null) {
71             this.rootHash = new byte[ROOT_HASH_SIZE];
72         } else {
73             this.rootHash = Arrays.copyOf(rootHash, ROOT_HASH_SIZE);
74         }
75     }
76 
77     @Override
size()78     public int size() {
79         return Extension.EXTENSION_HEADER_SIZE + MERKLE_TREE_EXTENSION_DATA_SIZE;
80     }
81 
getMerkleTreeSize()82     public long getMerkleTreeSize() {
83         return merkleTreeSize;
84     }
85 
getMerkleTreeOffset()86     public long getMerkleTreeOffset() {
87         return merkleTreeOffset;
88     }
89 
setMerkleTreeOffset(long offset)90     public void setMerkleTreeOffset(long offset) {
91         this.merkleTreeOffset = offset;
92     }
93 
94     /**
95      * Converts MerkleTreeExtension to a newly created byte array
96      *
97      * @return Byte array representation of MerkleTreeExtension
98      */
99     @Override
toByteArray()100     public byte[] toByteArray() {
101         ByteBuffer bf = ByteBuffer.allocate(Extension.EXTENSION_HEADER_SIZE + MERKLE_TREE_EXTENSION_DATA_SIZE)
102             .order(ByteOrder.LITTLE_ENDIAN);
103         bf.put(super.toByteArray());
104         bf.putLong(this.merkleTreeSize);
105         bf.putLong(this.merkleTreeOffset);
106         bf.put(this.rootHash);
107         return bf.array();
108     }
109 
110     /**
111      * Init the MerkleTreeExtension by a byte array
112      *
113      * @param bytes Byte array representation of a MerkleTreeExtension object
114      * @return a newly created MerkleTreeExtension object
115      * @throws VerifyCodeSignException parsing result invalid
116      */
fromByteArray(byte[] bytes)117     public static MerkleTreeExtension fromByteArray(byte[] bytes) throws VerifyCodeSignException {
118         ByteBuffer bf = ByteBuffer.allocate(bytes.length).order(ByteOrder.LITTLE_ENDIAN);
119         bf.put(bytes);
120         bf.rewind();
121         long inMerkleTreeSize = bf.getLong();
122         if (inMerkleTreeSize % CodeSignBlock.PAGE_SIZE_4K != 0) {
123             throw new VerifyCodeSignException("merkleTreeSize is not a multiple of 4096");
124         }
125         long inMerkleTreeOffset = bf.getLong();
126         if (inMerkleTreeOffset % CodeSignBlock.PAGE_SIZE_4K != 0) {
127             throw new VerifyCodeSignException("merkleTreeOffset is not a aligned to 4096");
128         }
129         byte[] inRootHash = new byte[ROOT_HASH_SIZE];
130         bf.get(inRootHash);
131         return new MerkleTreeExtension(inMerkleTreeSize, inMerkleTreeOffset, inRootHash);
132     }
133 
134     /**
135      * Return a string representation of the object
136      *
137      * @return string representation of the object
138      */
139     @Override
toString()140     public String toString() {
141         return String.format(Locale.ROOT, "MerkleTreeExtension: merkleTreeSize[%d], merkleTreeOffset[%d],"
142                 + " rootHash[%s]", this.merkleTreeSize, this.merkleTreeOffset, Arrays.toString(this.rootHash));
143     }
144 }
145