• 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 import com.ohos.hapsigntool.codesigning.utils.NumberUtils;
20 
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import java.util.Arrays;
24 import java.util.Locale;
25 
26 /**
27  * Merkle tree extension is a type of Extension to store a merkle tree's information, i.e. size and root hash, ect.
28  * <p>
29  * structure
30  * <p>
31  * 1) u32 type
32  * <p>
33  * 2) u64 merkleTreeSize: the size of merkle tree
34  * <p>
35  * 3) u64 merkleTreeOffset: offset of the merkle tree by the start of the file.
36  * <p>
37  * 4) u8[64] rootHash: merkle tree root hash
38  *
39  * @since 2023/09/08
40  */
41 public class MerkleTreeExtension extends Extension {
42     /**
43      * Type of MerkleTreeExtension
44      */
45     public static final int MERKLE_TREE_INLINED = 0x1;
46 
47     /**
48      * Byte size of MerkleTreeExtension including merkleTreeSize, offset and root hash.
49      */
50     public static final int MERKLE_TREE_EXTENSION_DATA_SIZE = 80;
51 
52     private static final int ROOT_HASH_SIZE = 64;
53 
54     private final long merkleTreeSize;
55 
56     private long merkleTreeOffset;
57 
58     private byte[] rootHash;
59 
60     /**
61      * Constructor for MerkleTreeExtension
62      *
63      * @param merkleTreeSize   Byte array representation of merkle tree
64      * @param merkleTreeOffset merkle tree offset based on file start
65      * @param rootHash         Root hash of the merkle tree
66      */
MerkleTreeExtension(long merkleTreeSize, long merkleTreeOffset, byte[] rootHash)67     public MerkleTreeExtension(long merkleTreeSize, long merkleTreeOffset, byte[] rootHash) {
68         super(MERKLE_TREE_INLINED, MERKLE_TREE_EXTENSION_DATA_SIZE);
69         this.merkleTreeSize = merkleTreeSize;
70         this.merkleTreeOffset = merkleTreeOffset;
71         if (rootHash == null) {
72             this.rootHash = new byte[ROOT_HASH_SIZE];
73         } else {
74             this.rootHash = Arrays.copyOf(rootHash, ROOT_HASH_SIZE);
75         }
76     }
77 
78     @Override
size()79     public int size() {
80         return Extension.EXTENSION_HEADER_SIZE + MERKLE_TREE_EXTENSION_DATA_SIZE;
81     }
82 
getMerkleTreeSize()83     public long getMerkleTreeSize() {
84         return merkleTreeSize;
85     }
86 
getMerkleTreeOffset()87     public long getMerkleTreeOffset() {
88         return merkleTreeOffset;
89     }
90 
setMerkleTreeOffset(long offset)91     public void setMerkleTreeOffset(long offset) {
92         this.merkleTreeOffset = offset;
93     }
94 
95     /**
96      * Converts MerkleTreeExtension to a newly created byte array
97      *
98      * @return Byte array representation of MerkleTreeExtension
99      */
100     @Override
toByteArray()101     public byte[] toByteArray() {
102         ByteBuffer bf = ByteBuffer.allocate(size()).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 (!NumberUtils.isMultiple4K(inMerkleTreeSize)) {
123             throw new VerifyCodeSignException("merkleTreeSize is not a multiple of 4096");
124         }
125         long inMerkleTreeOffset = bf.getLong();
126         if (!NumberUtils.isMultiple4K(inMerkleTreeOffset)) {
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