BinVerifier.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace MV485.util
  9. {
  10. //+------------------------+ ← Offset 0x000000
  11. //| Image Header | 固定32字节
  12. //+------------------------+ ← Offset 0x000020
  13. //| Padding | 填充到 header-size 对齐(例如 0x400)
  14. //+------------------------+ ← Offset 0x000400
  15. //| Image Payload | 实际的 bin 内容(运行代码)
  16. //+------------------------+
  17. //| TLV Info | 包括哈希、签名等(SHA256、ECDSA 等)
  18. //+------------------------+
  19. //| TLV Entries | 一个或多个 TLV 条目
  20. //+------------------------+
  21. //偏移 | 长度 | 字段名 | 描述
  22. //0x00 | 4 | ih_magic | 魔数 0x96F3B83D
  23. //0x04 | 4 | ih_load_addr | 加载地址(对于 RAM Load 有用)
  24. //0x08 | 2 | ih_hdr_size | 头部大小,一般为 0x400
  25. //0x0A | 2 | _pad1 | 保留字段
  26. //0x0C | 4 | ih_img_size | 镜像内容长度(不含头部)
  27. //0x10 | 4 | ih_flags | 标志位,如是否加密
  28. //0x14 | 1 | iv_major | 主版本号
  29. //0x15 | 1 | iv_minor | 次版本号
  30. //0x16 | 2 | iv_revision | 修订号
  31. //0x18 | 4 | iv_build_num | 构建号
  32. //0x1C | 4 | _pad2 | 保留字段
  33. //3D B8 F3 96 ← ih_magic = 0x96F3B83D
  34. //00 00 00 00 ← ih_load_addr = 0x00000000
  35. //04 00 ← ih_hdr_size = 0x0004(注意实际是 0x400)
  36. //00 00
  37. //A0 69 0A 00 ← ih_img_size = 0x000A69A0(约680KB)
  38. //00 00 00 00 ← ih_flags = 0
  39. //5C 5B 5A 00 ← version:iv_major=0x5C, iv_minor=0x5B, iv_revision=0x005A
  40. //...
  41. public class ImageHeader
  42. {
  43. public uint Magic; // 0x00 固定 magic: 0x96f3b83d
  44. public uint LoadAddr; // // 0x04 固件加载地址
  45. public ushort HeaderSize; // 0x08 Header 大小(如 0x400)
  46. public ushort Pad1; // 0x0A 对齐用
  47. public uint ImageSize; // 0x0C 固件正文大小(不含 Header)
  48. public uint Flags; // 0x10 标志位
  49. public byte VersionMajor; // 0x14~0x1B 版本号(major/minor/revision/build)
  50. public byte VersionMinor;
  51. public ushort VersionRevision;
  52. public uint VersionBuildNum;
  53. public uint Pad2;
  54. public static ImageHeader FromBinaryReader(BinaryReader reader)
  55. {
  56. return new ImageHeader
  57. {
  58. Magic = reader.ReadUInt32(),
  59. LoadAddr = reader.ReadUInt32(),
  60. HeaderSize = reader.ReadUInt16(),
  61. Pad1 = reader.ReadUInt16(),
  62. ImageSize = reader.ReadUInt32(),
  63. Flags = reader.ReadUInt32(),
  64. VersionMajor = reader.ReadByte(),
  65. VersionMinor = reader.ReadByte(),
  66. VersionRevision = reader.ReadUInt16(),
  67. VersionBuildNum = reader.ReadUInt32(),
  68. Pad2 = reader.ReadUInt32()
  69. };
  70. }
  71. }
  72. public class TlvInfo
  73. {
  74. public ushort Magic; // 0x6907
  75. public ushort TotalLength; // TLV区总长度(包括这4字节)
  76. public static TlvInfo FromBinaryReader(BinaryReader reader)
  77. {
  78. return new TlvInfo
  79. {
  80. Magic = reader.ReadUInt16(),
  81. TotalLength = reader.ReadUInt16()
  82. };
  83. }
  84. }
  85. //尾部 TLV 区域结构
  86. //每项4字节头 + 数据
  87. //类型(it_type) | 含义
  88. //0x01 | 公钥哈希
  89. //0x10 | 镜像 SHA256
  90. //0x22 | ECDSA256 签名
  91. //0x20 | RSA2048 签名(PSS)
  92. public class TlvEntry
  93. {
  94. public byte Type; // 类型,如 0x10 表示 SHA256,0x22 表示 ECDSA256
  95. public byte Pad; // 保留
  96. public ushort Length; // 后续数据长度
  97. public byte[] Value;
  98. public static TlvEntry FromBinaryReader(BinaryReader reader)
  99. {
  100. var entry = new TlvEntry
  101. {
  102. Type = reader.ReadByte(),
  103. Pad = reader.ReadByte(),
  104. Length = reader.ReadUInt16()
  105. };
  106. entry.Value = reader.ReadBytes(entry.Length);
  107. return entry;
  108. }
  109. }
  110. public class BinVerifier
  111. {
  112. public static bool VerifyBin(string binFilePath, out string expectedHashHex, out string actualHashHex)
  113. {
  114. expectedHashHex = "";
  115. actualHashHex = "";
  116. using (var fs = new FileStream(binFilePath, FileMode.Open, FileAccess.Read))
  117. using (var reader = new BinaryReader(fs))
  118. {
  119. // Step 1: 读取 image_header
  120. var header = ImageHeader.FromBinaryReader(reader);
  121. fs.Position = 0;
  122. var fullHeader = reader.ReadBytes(header.HeaderSize);
  123. // Step 2: 读取 image body
  124. var body = reader.ReadBytes((int)header.ImageSize);
  125. // Step 3: 读取 TLV info
  126. var tlvInfo = TlvInfo.FromBinaryReader(reader);
  127. if (tlvInfo.Magic != 0x6907)
  128. throw new InvalidDataException("Invalid TLV magic number.");
  129. int tlvRemaining = tlvInfo.TotalLength - 4;
  130. byte[] hashValue = null;
  131. while (tlvRemaining > 0)
  132. {
  133. var entry = TlvEntry.FromBinaryReader(reader);
  134. if (entry.Type == 0x10 && entry.Length == 32) // SHA256 type
  135. {
  136. hashValue = entry.Value;
  137. break;
  138. }
  139. tlvRemaining -= 4 + entry.Length;
  140. }
  141. if (hashValue == null)
  142. throw new InvalidDataException("SHA256 hash not found in TLV.");
  143. expectedHashHex = BitConverter.ToString(hashValue).Replace("-", "").ToLowerInvariant();
  144. // Step 4: 计算 SHA256(header + body)
  145. using (var sha = SHA256.Create())
  146. {
  147. var calculatedHash = sha.ComputeHash(fullHeader.Concat(body).ToArray());
  148. actualHashHex = BitConverter.ToString(calculatedHash).Replace("-", "").ToLowerInvariant();
  149. }
  150. return expectedHashHex == actualHashHex;
  151. }
  152. }
  153. }
  154. //------------------------------
  155. }