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