• 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.fsverity.FsVerityDescriptor;
20 import com.ohos.hapsigntool.codesigning.fsverity.FsVerityGenerator;
21 
22 import java.nio.ByteBuffer;
23 import java.nio.ByteOrder;
24 import java.util.Locale;
25 
26 /**
27  * Fs-verity info segment contains information of fs-verity protection
28  * More information of fs-verity can be found <a herf="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">here</a>
29  * <p>
30  * Structure
31  * <p>
32  * 1) u32 magic: magic number
33  * <p>
34  * 2) u8 version: fs-verity version
35  * <p>
36  * 3) u8 hashAlgorithm: hash algorithm to use for the Merkle tree
37  * <p>
38  * 4) u8 log2BlockSize: log2 of size of data and tree blocks
39  * <p>
40  * 5) u8[] reserved: for reservation
41  *
42  * @since 2023/09/08
43  */
44 public class FsVerityInfoSegment {
45     /**
46      * fs-verity info segment size in bytes
47      */
48     public static final int FS_VERITY_INFO_SEGMENT_SIZE = 64;
49 
50     // lower 4 bytes of the MD5 result of string "fs-verity info segment" (1E38 31AB)
51     private static final int MAGIC = (0x1E38 << 16) + (0x31AB);
52 
53     private static final int RESERVED_BYTE_ARRAY_LENGTH = 57;
54 
55     private int magic = MAGIC;
56 
57     private byte hashAlgorithm;
58 
59     private byte version;
60 
61     private byte log2BlockSize;
62 
63     private byte[] reserved = new byte[RESERVED_BYTE_ARRAY_LENGTH];
64 
65     /**
66      * Default constructor
67      */
FsVerityInfoSegment()68     public FsVerityInfoSegment() {
69     }
70 
FsVerityInfoSegment(byte version, byte hashAlgorithm, byte log2BlockSize)71     public FsVerityInfoSegment(byte version, byte hashAlgorithm, byte log2BlockSize) {
72         this(MAGIC, version, hashAlgorithm, log2BlockSize, new byte[RESERVED_BYTE_ARRAY_LENGTH]);
73     }
74 
75     /**
76      * Constructor of FsVerityInfoSegment
77      *
78      * @param magic         magic num
79      * @param version       version of fs-verity
80      * @param hashAlgorithm hash algorithm to use for the Merkle tree
81      * @param log2BlockSize log2 of size of data and tree blocks
82      * @param reserved      for reservation
83      */
FsVerityInfoSegment(int magic, byte version, byte hashAlgorithm, byte log2BlockSize, byte[] reserved)84     public FsVerityInfoSegment(int magic, byte version, byte hashAlgorithm, byte log2BlockSize, byte[] reserved) {
85         this.magic = magic;
86         this.version = version;
87         this.hashAlgorithm = hashAlgorithm;
88         this.log2BlockSize = log2BlockSize;
89         this.reserved = reserved;
90     }
91 
size()92     public int size() {
93         return FS_VERITY_INFO_SEGMENT_SIZE;
94     }
95 
96     /**
97      * Converts FsVerityInfoSegment to a newly created byte array
98      *
99      * @return Byte array representation of FsVerityInfoSegment
100      */
toByteArray()101     public byte[] toByteArray() {
102         ByteBuffer bf = ByteBuffer.allocate(FS_VERITY_INFO_SEGMENT_SIZE).order(ByteOrder.LITTLE_ENDIAN);
103         bf.putInt(this.magic);
104         bf.put(version);
105         bf.put(hashAlgorithm);
106         bf.put(log2BlockSize);
107         bf.put(reserved);
108         return bf.array();
109     }
110 
111     /**
112      * Init the FsVerityInfoSegment by a byte array
113      *
114      * @param bytes Byte array representation of a FsVerityInfoSegment object
115      * @return a newly created FsVerityInfoSegment object
116      * @throws VerifyCodeSignException parsing result invalid
117      */
fromByteArray(byte[] bytes)118     public static FsVerityInfoSegment fromByteArray(byte[] bytes) throws VerifyCodeSignException {
119         if (bytes.length != FS_VERITY_INFO_SEGMENT_SIZE) {
120             throw new VerifyCodeSignException("Invalid size of FsVerityInfoSegment");
121         }
122         ByteBuffer bf = ByteBuffer.allocate(bytes.length).order(ByteOrder.LITTLE_ENDIAN);
123         bf.put(bytes);
124         bf.rewind();
125         int inMagic = bf.getInt();
126         if (inMagic != MAGIC) {
127             throw new VerifyCodeSignException("Invalid magic number of FsVerityInfoSegment");
128         }
129         byte inVersion = bf.get();
130         if (inVersion != FsVerityDescriptor.VERSION) {
131             throw new VerifyCodeSignException("Invalid version of FsVerityInfoSegment");
132         }
133         byte inHashAlgorithm = bf.get();
134         if (inHashAlgorithm != FsVerityGenerator.getFsVerityHashAlgorithm()) {
135             throw new VerifyCodeSignException("Invalid hashAlgorithm of FsVerityInfoSegment");
136         }
137         byte inLog2BlockSize = bf.get();
138         if (inLog2BlockSize != FsVerityGenerator.getLog2BlockSize()) {
139             throw new VerifyCodeSignException("Invalid log2BlockSize of FsVerityInfoSegment");
140         }
141         byte[] inReservedBytes = new byte[RESERVED_BYTE_ARRAY_LENGTH];
142         bf.get(inReservedBytes);
143         return new FsVerityInfoSegment(inMagic, inVersion, inHashAlgorithm, inLog2BlockSize, inReservedBytes);
144     }
145 
146     /**
147      * Return a string representation of the object
148      *
149      * @return string representation of the object
150      */
toString()151     public String toString() {
152         return String.format(Locale.ROOT, "FsVerityInfoSeg: magic[%d], version[%d], hashAlg[%d], log2BlockSize[%d]",
153             this.magic, this.version, this.hashAlgorithm, this.log2BlockSize);
154     }
155 }
156