• 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.fsverity;
17 
18 import com.ohos.hapsigntool.codesigning.datastructure.PageInfoExtension;
19 import com.ohos.hapsigntool.codesigning.exception.CodeSignErrMsg;
20 import com.ohos.hapsigntool.codesigning.exception.FsVerityDigestException;
21 import com.ohos.hapsigntool.codesigning.exception.PageInfoException;
22 import com.ohos.hapsigntool.codesigning.utils.DigestUtils;
23 
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.security.NoSuchAlgorithmException;
27 
28 /**
29  * FsVerity data generator supper class
30  *
31  * @since 2023/06/05
32  */
33 public class FsVerityGenerator {
34     /**
35      * FsVerity hash algorithm
36      */
37     private static final FsVerityHashAlgorithm FS_VERITY_HASH_ALGORITHM = FsVerityHashAlgorithm.SHA256;
38 
39     private static final byte LOG_2_OF_FSVERITY_HASH_PAGE_SIZE = 12;
40 
41     /**
42      * salt for hashing one page
43      */
44     protected byte[] salt = null;
45 
46     private byte[] fsVerityDigest = null;
47 
48     private byte[] fsVerityDigestV2 = null;
49 
50     private byte[] treeBytes = null;
51 
52     private byte[] rootHash = null;
53 
54     private PageInfoExtension pageInfoExtension;
55 
56     /**
57      * Constructor for FsVerityGenerator
58      *
59      * @param pg PageInfoExtension
60      */
setPageInfoExtension(PageInfoExtension pg)61     public void setPageInfoExtension(PageInfoExtension pg) {
62         this.pageInfoExtension = pg;
63     }
64 
65     /**
66      * generate merkle tree of given input
67      *
68      * @param inputStream           input stream for generate merkle tree
69      * @param size                  total size of input stream
70      * @param fsVerityHashAlgorithm hash algorithm for FsVerity
71      * @return merkle tree
72      * @throws FsVerityDigestException if error
73      */
generateMerkleTree(InputStream inputStream, long size, FsVerityHashAlgorithm fsVerityHashAlgorithm)74     public MerkleTree generateMerkleTree(InputStream inputStream, long size,
75         FsVerityHashAlgorithm fsVerityHashAlgorithm) throws FsVerityDigestException {
76         MerkleTree merkleTree;
77         try (MerkleTreeBuilder builder = new MerkleTreeBuilder()) {
78             merkleTree = builder.generateMerkleTree(inputStream, size, fsVerityHashAlgorithm);
79         } catch (IOException e) {
80             throw new FsVerityDigestException(e.getMessage(), e);
81         } catch (NoSuchAlgorithmException e) {
82             throw new FsVerityDigestException(
83                 CodeSignErrMsg.ALGORITHM_NOT_SUPPORT_ERROR.toString(fsVerityHashAlgorithm.getHashAlgorithm()), e);
84         }
85         return merkleTree;
86     }
87 
88     /**
89      * generate FsVerity digest of given input
90      *
91      * @param inputStream   input stream for generate FsVerity digest
92      * @param size          total size of input stream
93      * @param fsvTreeOffset merkle tree raw bytes offset based on the start of file
94      * @throws FsVerityDigestException fsVerity digest error
95      * @throws PageInfoException page info error
96      */
generateFsVerityDigest(InputStream inputStream, long size, long fsvTreeOffset)97     public void generateFsVerityDigest(InputStream inputStream, long size, long fsvTreeOffset)
98         throws FsVerityDigestException, PageInfoException {
99         MerkleTree merkleTree;
100         if (size == 0) {
101             merkleTree = new MerkleTree(null, null, FS_VERITY_HASH_ALGORITHM);
102         } else {
103             merkleTree = generateMerkleTree(inputStream, size, FS_VERITY_HASH_ALGORITHM);
104         }
105         int flags = fsvTreeOffset == 0 ? 0 : FsVerityDescriptor.FLAG_STORE_MERKLE_TREE_OFFSET;
106         // sign size is 0, cs version is 0
107         FsVerityDescriptor.Builder builder = new FsVerityDescriptor.Builder().setFileSize(size)
108             .setHashAlgorithm(FS_VERITY_HASH_ALGORITHM.getId())
109             .setLog2BlockSize(LOG_2_OF_FSVERITY_HASH_PAGE_SIZE)
110             .setSaltSize((byte) getSaltSize())
111             .setSalt(salt)
112             .setRawRootHash(merkleTree.rootHash)
113             .setFlags(flags)
114             .setMerkleTreeOffset(fsvTreeOffset);
115         try {
116             byte[] fsVerityDescriptor = builder.build().getDiscByte();
117             byte[] digest = DigestUtils.computeDigest(fsVerityDescriptor, FS_VERITY_HASH_ALGORITHM.getHashAlgorithm());
118             fsVerityDigest = FsVerityDigest.getFsVerityDigest(FS_VERITY_HASH_ALGORITHM.getId(), digest);
119         } catch (NoSuchAlgorithmException e) {
120             throw new FsVerityDigestException(
121                 CodeSignErrMsg.ALGORITHM_NOT_SUPPORT_ERROR.toString(FS_VERITY_HASH_ALGORITHM.getHashAlgorithm()), e);
122         }
123         if (pageInfoExtension != null && flags != 0) {
124             PageInfoExtension.valid(pageInfoExtension, size);
125             try {
126                 byte[] fsVerityDescriptorV2 = builder.build()
127                     .getDiscByteCsv2(pageInfoExtension.getMapOffset(), pageInfoExtension.getMapSize(),
128                         pageInfoExtension.getUnitSize());
129                 byte[] digest = DigestUtils.computeDigest(fsVerityDescriptorV2,
130                     FS_VERITY_HASH_ALGORITHM.getHashAlgorithm());
131                 fsVerityDigestV2 = FsVerityDigest.getFsVerityDigest(FS_VERITY_HASH_ALGORITHM.getId(), digest);
132             } catch (NoSuchAlgorithmException e) {
133                 throw new FsVerityDigestException(
134                     CodeSignErrMsg.ALGORITHM_NOT_SUPPORT_ERROR.toString(FS_VERITY_HASH_ALGORITHM.getHashAlgorithm()),
135                     e);
136             }
137         }
138         treeBytes = merkleTree.tree;
139         rootHash = merkleTree.rootHash;
140     }
141 
142     /**
143      * Get FsVerity digest
144      *
145      * @return bytes of FsVerity digest
146      */
getFsVerityDigest()147     public byte[] getFsVerityDigest() {
148         return fsVerityDigest;
149     }
150 
151     /**
152      * Get FsVerity digest
153      *
154      * @return bytes of FsVerity digest
155      */
getFsVerityDigestV2()156     public byte[] getFsVerityDigestV2() {
157         return fsVerityDigestV2;
158     }
159 
160     /**
161      * Get merkle tree in bytes
162      *
163      * @return bytes of merkle tree
164      */
getTreeBytes()165     public byte[] getTreeBytes() {
166         return treeBytes;
167     }
168 
169     /**
170      * Get merkle tree rootHash in bytes
171      *
172      * @return bytes of merkle tree rootHash
173      */
getRootHash()174     public byte[] getRootHash() {
175         return rootHash;
176     }
177 
getSalt()178     public byte[] getSalt() {
179         return salt;
180     }
181 
182     /**
183      * Returns byte size of salt
184      *
185      * @return byte size of salt
186      */
getSaltSize()187     public int getSaltSize() {
188         return this.salt == null ? 0 : this.salt.length;
189     }
190 
191     /**
192      * Returns the id of fs-verity hash algorithm
193      *
194      * @return fs-verity hash algorithm id
195      */
getFsVerityHashAlgorithm()196     public static byte getFsVerityHashAlgorithm() {
197         return FS_VERITY_HASH_ALGORITHM.getId();
198     }
199 
200     /**
201      * Returns the log2 of size of data and tree blocks
202      *
203      * @return log2 of size of data and tree blocks
204      */
getLog2BlockSize()205     public static byte getLog2BlockSize() {
206         return LOG_2_OF_FSVERITY_HASH_PAGE_SIZE;
207     }
208 }
209