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.Locale; 23 24 /** 25 * Hap info segment 26 * <p> 27 * Structure 28 * <p> 29 * 1) u32 magic: magic number 30 * <p> 31 * 2) SignInfo hapSignInfo: data struct of sign info, refer to SignInfo.java 32 * 33 * @since 2023/09/08 34 */ 35 public class HapInfoSegment { 36 private static final int MAGIC_NUM_BYTES = 4; 37 38 /** 39 * lower 4 bytes of the MD5 result of string "hap info segment" (C1B5 CC66) 40 */ 41 private static final int MAGIC_NUM = (0xC1B5 << 16) + 0xCC66; 42 43 private int magic = MAGIC_NUM; 44 45 private SignInfo hapSignInfo; 46 47 /** 48 * Default constructor of HapInfoSegment 49 */ HapInfoSegment()50 public HapInfoSegment() { 51 this(MAGIC_NUM, new SignInfo(0, 0, 0, null, null)); 52 } 53 54 /** 55 * Default constructor of HapInfoSegment 56 * 57 * @param magic magic number 58 * @param hapSignInfo hap sign info 59 */ HapInfoSegment(int magic, SignInfo hapSignInfo)60 public HapInfoSegment(int magic, SignInfo hapSignInfo) { 61 this.magic = magic; 62 this.hapSignInfo = hapSignInfo; 63 } 64 setSignInfo(SignInfo signInfo)65 public void setSignInfo(SignInfo signInfo) { 66 this.hapSignInfo = signInfo; 67 } 68 getSignInfo()69 public SignInfo getSignInfo() { 70 return hapSignInfo; 71 } 72 73 /** 74 * Returns byte size of HapInfoSegment 75 * 76 * @return byte size of HapInfoSegment 77 */ size()78 public int size() { 79 return MAGIC_NUM_BYTES + hapSignInfo.size(); 80 } 81 82 /** 83 * Converts HapInfoSegment to a newly created byte array 84 * 85 * @return Byte array representation of HapInfoSegment 86 */ toByteArray()87 public byte[] toByteArray() { 88 byte[] hapSignInfoByteArray = this.hapSignInfo.toByteArray(); 89 // For now, only hap info segment has a merkle tree extension. So info segment 90 // has none extension. 91 ByteBuffer bf = ByteBuffer.allocate(MAGIC_NUM_BYTES + hapSignInfoByteArray.length) 92 .order(ByteOrder.LITTLE_ENDIAN); 93 bf.putInt(magic); 94 bf.put(hapSignInfoByteArray); 95 return bf.array(); 96 } 97 98 /** 99 * Init the HapInfoSegment by a byte array 100 * 101 * @param bytes Byte array representation of a HapInfoSegment object 102 * @return a newly created HapInfoSegment object 103 * @throws VerifyCodeSignException parsing result invalid 104 */ fromByteArray(byte[] bytes)105 public static HapInfoSegment fromByteArray(byte[] bytes) throws VerifyCodeSignException { 106 ByteBuffer bf = ByteBuffer.allocate(bytes.length).order(ByteOrder.LITTLE_ENDIAN); 107 bf.put(bytes); 108 bf.rewind(); 109 int inMagic = bf.getInt(); 110 if (inMagic != MAGIC_NUM) { 111 throw new VerifyCodeSignException("Invalid magic number of HapInfoSegment"); 112 } 113 if (bytes.length <= MAGIC_NUM_BYTES) { 114 throw new VerifyCodeSignException("Invalid bytes size of HapInfoSegment"); 115 } 116 byte[] hapSignInfoByteArray = new byte[bytes.length - MAGIC_NUM_BYTES]; 117 bf.get(hapSignInfoByteArray); 118 SignInfo inHapSignInfo = SignInfo.fromByteArray(hapSignInfoByteArray); 119 if (inHapSignInfo.getDataSize() % CodeSignBlock.PAGE_SIZE_4K != 0) { 120 throw new VerifyCodeSignException( 121 String.format(Locale.ROOT, "Invalid dataSize number of HapInfoSegment, not a multiple of 4096: %d", 122 inHapSignInfo.getDataSize())); 123 } 124 if (inHapSignInfo.getExtensionNum() != SignInfo.MAX_EXTENSION_NUM) { 125 throw new VerifyCodeSignException("Invalid extensionNum of HapInfoSegment"); 126 } 127 if (inHapSignInfo.getExtensionByType(MerkleTreeExtension.MERKLE_TREE_INLINED) == null) { 128 throw new VerifyCodeSignException("No merkle tree extension is found in HapInfoSegment"); 129 } 130 return new HapInfoSegment(inMagic, inHapSignInfo); 131 } 132 133 /** 134 * Return a string representation of the object 135 * 136 * @return string representation of the object 137 */ toString()138 public String toString() { 139 return String.format(Locale.ROOT, "HapInfoSegment: magic[%d], signInfo[%s]", this.magic, 140 this.hapSignInfo.toString()); 141 } 142 } 143