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