public bool VerifyXvcHash(bool rehash = false) { if (!IsXvcFile) { return(true); } ulong hashTreeSize = HashTreePageCount * PAGE_SIZE; var ms = new MemoryStream(); var msIo = new IO(ms); msIo.Writer.WriteStruct(XvcInfo); // fix region headers to match pre-hashtable for (int i = 0; i < XvcInfo.RegionCount; i++) { var region = RegionHeaders[i]; region.Hash = 0; if (IsDataIntegrityEnabled) { if (HashTreeOffset >= region.Offset && region.Offset + region.Length > HashTreeOffset) { region.Length -= hashTreeSize; } else if (region.Offset > HashTreeOffset) { region.Offset -= hashTreeSize; } } msIo.Writer.WriteStruct(region); } for (int i = 0; i < XvcInfo.UpdateSegmentCount; i++) { var segment = UpdateSegments[i]; var hashTreeEnd = XvdMath.BytesToPages(HashTreeOffset) + HashTreePageCount; if (segment.PageNum >= hashTreeEnd) { segment.PageNum -= (uint)HashTreePageCount; } segment.Hash = 0; msIo.Writer.WriteStruct(segment); } if (RegionSpecifiers != null) { for (int i = 0; i < XvcInfo.RegionSpecifierCount; i++) { msIo.Writer.WriteStruct(RegionSpecifiers[i]); } } if (Header.XvcDataLength > msIo.Stream.Length) { msIo.Stream.SetLength(Header.XvcDataLength); } if (IsDataIntegrityEnabled) { // remove hash table offset from the special regions if (XvcInfo.InitialPlayOffset > HashTreeOffset) { msIo.Stream.Position = 0xD28; msIo.Writer.Write(XvcInfo.InitialPlayOffset - hashTreeSize); } if (XvcInfo.PreviewOffset > HashTreeOffset) { msIo.Stream.Position = 0xD40; msIo.Writer.Write(XvcInfo.PreviewOffset - hashTreeSize); } } byte[] xvcData = ms.ToArray(); msIo.Dispose(); byte[] hash = HashUtils.ComputeSha256(xvcData); bool isValid = Header.OriginalXvcDataHash.IsEqualTo(hash); if (rehash) { Header.OriginalXvcDataHash = hash; } return(isValid); //todo: investigate why this gets the correct hash for dev XVCs but fails for retail ones, might be to do with retail XVC data having a content ID that doesn't match with VDUID/UDUID }
public bool Resign(byte[] key, string keyType) { var headerData = GetHeaderWithoutSignature(); return(HashUtils.SignData(key, keyType, headerData, out Signature)); }