public static R<Licenses, string> Parse(ReadOnlySpan<byte> data) { if (data.Length < 1) return "License too short"; var version = data[0]; if (version != 1) return "Unsupported version"; // Read licenses var res = new Licenses { Blocks = new List<LicenseBlock>() }; data = data.Slice(1); while (data.Length > 0) { // Read next license var result = LicenseBlock.Parse(data); if (!result.Ok) return result.Error; var (license, len) = result.Value; // TODO Check valid times res.Blocks.Add(license); data = data.Slice(len); } return res; }
public static R<(LicenseBlock block, int read), string> Parse(ReadOnlySpan<byte> data) { if (data.Length < MinBlockLen) { return "License too short"; } if (data[0] != 0) { return $"Wrong key kind {data[0]} in license"; } LicenseBlock block; int read; switch (data[33]) { case 0: var result = ReadNullString(data.Slice(46)); if (!result.Ok) return result.Error; var nullStr = result.Value; block = new IntermediateLicenseBlock { Issuer = nullStr.str }; read = 5 + nullStr.read; break; case 2: if (!Enum.IsDefined(typeof(ServerLicenseType), data[42])) return $"Unknown license type {data[42]}"; result = ReadNullString(data.Slice(47)); if (!result.Ok) return result.Error; nullStr = result.Value; block = new ServerLicenseBlock { Issuer = result.Value.str, LicenseType = (ServerLicenseType)data[42] }; read = 6 + nullStr.read; break; case 32: block = new EphemeralLicenseBlock(); read = 0; break; default: return $"Invalid license block type {data[33]}"; } block.NotValidBefore = Util.UnixTimeStart.AddSeconds(BinaryPrimitives.ReadUInt32BigEndian(data.Slice(34)) + 0x50e22700uL); block.NotValidAfter = Util.UnixTimeStart.AddSeconds(BinaryPrimitives.ReadUInt32BigEndian(data.Slice(38)) + 0x50e22700uL); if (block.NotValidAfter < block.NotValidBefore) return "License times are invalid"; block.Key = data.Slice(1, 32).ToArray(); var allLen = MinBlockLen + read; var hash = Ts3Crypt.Hash512It(data.Slice(1, allLen - 1).ToArray()); block.Hash = hash.AsSpan(0, 32).ToArray(); return (block, allLen); }