Made preparations for unscrambling TS Packets in case the key is known.
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 3m17s

This commit is contained in:
feyris-tan 2025-12-28 09:49:07 +01:00
parent cd2055a07a
commit 376201cfa5
7 changed files with 293 additions and 47 deletions

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.src.Mpeg2.PacketFilter;
using skyscraper8.Skyscraper.Security.Cryptography;
namespace skyscraper8.Mpeg2.PacketFilter
{
internal class BissDescrambleFilter : IPacketFilter
{
public BissDescrambleFilter(byte[] key, params uint[] pids)
{
this.key = key;
if (pids != null)
{
if (pids.Length > 0)
{
_pidsToDescramble = new List<uint>();
_pidsToDescramble.AddRange(pids);
}
}
}
private byte[] key;
private List<uint> _pidsToDescramble;
private bool CheckPid(uint pid)
{
if (_pidsToDescramble == null)
return true;
else
return _pidsToDescramble.Contains(pid);
}
private DvbCsa2 csa2;
public bool PassPacket(TsPacket packet)
{
if (packet.TSC == 0)
return true;
if (!CheckPid(packet.PID))
return true;
//Okay, we actually need to do something...
if (csa2 == null)
{
csa2 = new DvbCsa2(key.Length == 8 ? DvbCsa2.EntropyMode.FULL_CW : DvbCsa2.EntropyMode.REDUCE_ENTROPY);
csa2.SetKeyImpl(key);
}
int retsize = 0;
byte[] unscrambled = new byte[packet.Payload.Length];
csa2.DecryptImpl(packet.Payload, packet.Payload.Length, unscrambled, unscrambled.Length, ref retsize);
packet.SetUnscrambled(unscrambled);
return true;
}
}
}

View File

@ -48,18 +48,18 @@ namespace skyscraper5.Mpeg2
//Unit start //Unit start
} }
int payloadOffset = 4; PayloadOffset = 4;
if (PayloadUnitStart) if (PayloadUnitStart)
{ {
PayloadStartOffset = buffer[4] & 0xff; PayloadStartOffset = buffer[4] & 0xff;
payloadOffset++; PayloadOffset++;
} }
switch (AdaptionFieldControl) switch (AdaptionFieldControl)
{ {
case 1: case 1:
br.Position = payloadOffset; br.Position = PayloadOffset;
long PayloadLengthB = 188 - payloadOffset; long PayloadLengthB = 188 - PayloadOffset;
Payload = br.ReadBytes(PayloadLengthB); Payload = br.ReadBytes(PayloadLengthB);
break; break;
case 2: case 2:
@ -74,9 +74,9 @@ namespace skyscraper5.Mpeg2
TEI = true; TEI = true;
break; break;
} }
payloadOffset += Adaption.Length; PayloadOffset += Adaption.Length;
br.Position = payloadOffset; br.Position = PayloadOffset;
long PayloadLength = (188 - payloadOffset); long PayloadLength = (188 - PayloadOffset);
Payload = br.ReadBytes((int)PayloadLength); Payload = br.ReadBytes((int)PayloadLength);
break; break;
default: default:
@ -99,7 +99,7 @@ namespace skyscraper5.Mpeg2
/// 2 = scrambled, even key /// 2 = scrambled, even key
/// 3 = scrambled, odd key /// 3 = scrambled, odd key
/// </summary> /// </summary>
public uint TSC { get; private set; } public uint TSC { get; internal set; }
public uint AdaptionFieldControl { get; private set; } public uint AdaptionFieldControl { get; private set; }
public uint Continuity { get; private set; } public uint Continuity { get; private set; }
public int PayloadStartOffset { get; private set; } public int PayloadStartOffset { get; private set; }
@ -108,6 +108,8 @@ namespace skyscraper5.Mpeg2
public byte[] RawPacket { get; private set; } public byte[] RawPacket { get; private set; }
public ulong Serial { get; private set; } public ulong Serial { get; private set; }
public int PayloadOffset { get; private set; }
/// <summary> /// <summary>
/// Retrieving the raw packet, including adaption field and Payload, but without the four byte header. /// Retrieving the raw packet, including adaption field and Payload, but without the four byte header.
/// </summary> /// </summary>
@ -118,5 +120,13 @@ namespace skyscraper5.Mpeg2
Array.Copy(RawPacket, 4, buffer, 0, 184); Array.Copy(RawPacket, 4, buffer, 0, 184);
return buffer; return buffer;
} }
public void SetUnscrambled(byte[] unscrambledPayload)
{
TSC = 0;
Payload = unscrambledPayload;
Array.Copy(unscrambledPayload, 0, RawPacket, PayloadOffset, unscrambledPayload.Length);
RawPacket[3] &= 0x3f;
}
} }
} }

View File

@ -11,7 +11,6 @@ using skyscraper5.Skyscraper.IO.TunerInterface;
using skyscraper5.Skyscraper.Plugins; using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.RecordingImporter; using skyscraper5.Skyscraper.RecordingImporter;
using skyscraper5.Skyscraper.Scraper; using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.FrameGrabber;
using skyscraper5.Skyscraper.Scraper.Storage.Filesystem; using skyscraper5.Skyscraper.Scraper.Storage.Filesystem;
using skyscraper5.Skyscraper.Scraper.Storage.InMemory; using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
using skyscraper5.Skyscraper.Webserver; using skyscraper5.Skyscraper.Webserver;
@ -24,15 +23,9 @@ using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Net.Sockets; using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using skyscraper5.Mpeg2.Descriptors;
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
using skyscraper8; using skyscraper8;
using skyscraper8.GSE; using skyscraper8.GSE;
using skyscraper8.SatIp;
using skyscraper8.SatIp.RtspResponses;
using skyscraper8.SimpleServiceDiscoveryProtocol;
using skyscraper8.Skyscraper.Math; using skyscraper8.Skyscraper.Math;
using skyscraper8.Skyscraper; using skyscraper8.Skyscraper;
using skyscraper8.Skyscraper.Security.AccessControl; using skyscraper8.Skyscraper.Security.AccessControl;
@ -46,40 +39,42 @@ namespace skyscraper5
private static void IntegrationTest() private static void IntegrationTest()
{ {
/*List<SsdpDevice> ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); SoftcamTestProgram softcamTestProgram = new SoftcamTestProgram();
foreach (SsdpDevice ssdpDevice in ssdpDevices) softcamTestProgram.Run();
{ /*List<SsdpDevice> ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList();
Console.WriteLine("SSDP device: {0}", ssdpDevice.Server); foreach (SsdpDevice ssdpDevice in ssdpDevices)
}*/ {
Console.WriteLine("SSDP device: {0}", ssdpDevice.Server);
}*/
//"urn:ses-com:device:SatIPServer:1" //"urn:ses-com:device:SatIPServer:1"
/*PluginManager pluginManager = PluginManager.GetInstance(); /*PluginManager pluginManager = PluginManager.GetInstance();
StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance();
ObjectStorageFactory objectStorageFactory = storageConnectionManager.GetDefaultObjectStorageFactory(); ObjectStorageFactory objectStorageFactory = storageConnectionManager.GetDefaultObjectStorageFactory();
ObjectStorage objectStorage = objectStorageFactory.CreateObjectStorage();*/ ObjectStorage objectStorage = objectStorageFactory.CreateObjectStorage();*/
/*url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11141, true, 23500); /*url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11141, true, 23500);
describe = rtspClient.GetDescribe(url); describe = rtspClient.GetDescribe(url);
sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol(); sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol();
rtcps = 0; rtcps = 0;
rtps = 0; rtps = 0;
setup = rtspClient.GetSetup(url); setup = rtspClient.GetSetup(url);
setup.OnRtcpPacket += ((data, length) => setup.OnRtcpPacket += ((data, length) =>
rtcps++); rtcps++);
setup.OnRtpPacket += (data, length) => setup.OnRtpPacket += (data, length) =>
rtps++; rtps++;
play = rtspClient.GetPlay(setup); play = rtspClient.GetPlay(setup);
Thread.Sleep(5000); Thread.Sleep(5000);
rtspClient.AutoReconnect = false; rtspClient.AutoReconnect = false;
rtspClient.GetTeardown(setup); rtspClient.GetTeardown(setup);
Console.WriteLine("{0} RTCPs", rtcps); Console.WriteLine("{0} RTCPs", rtcps);
Console.WriteLine("{0} RTPs", rtps);*/ Console.WriteLine("{0} RTPs", rtps);*/
//rtspClient.Dispose(); //rtspClient.Dispose();
} }
static void Main(string[] args) static void Main(string[] args)
@ -365,7 +360,7 @@ namespace skyscraper5
catalogueGenerator.Dispose(); catalogueGenerator.Dispose();
return; return;
} }
} }
/*Passing passing = new Passing(); /*Passing passing = new Passing();
if (!passing.Boot()) if (!passing.Boot())

View File

@ -38,5 +38,10 @@ namespace skyscraper8.Skyscraper.Security.AccessControl
{ {
return (int)Coordinate; return (int)Coordinate;
} }
public override string ToString()
{
return String.Format("F {0:X8} 00000000 {1}", Coordinate, BitConverter.ToString(Key).Replace("-", ""));
}
} }
} }

View File

@ -213,5 +213,22 @@ namespace skyscraper8.Skyscraper.Security.AccessControl
private HashSet<BissKey> _bissKeys; private HashSet<BissKey> _bissKeys;
public IReadOnlySet<BissKey> BissKeys => _bissKeys; public IReadOnlySet<BissKey> BissKeys => _bissKeys;
public byte[] FindBissKey(ushort transportStreamId, ushort networkId)
{
if (_bissKeys == null)
return null;
byte[] transportStreamIdBytes = BitConverter.GetBytes(transportStreamId);
byte[] networkIdBytes = BitConverter.GetBytes(networkId);
byte[] keyBytes = new byte[] { networkIdBytes[0], networkIdBytes[1], transportStreamIdBytes[0], transportStreamIdBytes[1] };
uint coordinate = BitConverter.ToUInt32(keyBytes);
BissKey bissKey = _bissKeys.FirstOrDefault(x => x.Coordinate == coordinate);
if (bissKey != null)
return bissKey.Key;
else
return null;
}
} }
} }

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Scraper;
using skyscraper8.Mpeg2.PacketFilter;
namespace skyscraper8.Skyscraper.Security.AccessControl
{
internal class SoftcamTestProgram
{
public void Run()
{
SoftcamKeyset softcamKeyset = SoftcamKeyset.GetInstance();
softcamKeyset.InitializeFromFile();
byte[] bissKey = softcamKeyset.FindBissKey(2, 85);
BissDescrambleFilter descrambler = new BissDescrambleFilter(bissKey);
FileInfo inputFile = new FileInfo("C:\\devel\\12380h_filtered.ts");
FileStream fileStream = inputFile.OpenRead();
byte[] buffer = new byte[188];
for (long i = 0; i < fileStream.Length; i += 188)
{
fileStream.Read(buffer, 0, 188);
TsPacket packet = new TsPacket(buffer);
descrambler.PassPacket(packet);
}
}
}
}

View File

@ -14,6 +14,7 @@ namespace skyscraper8.Skyscraper.Security.Cryptography
public const int KEY_BITS = 64; //!< DVB CSA-2 control words size in bits. public const int KEY_BITS = 64; //!< DVB CSA-2 control words size in bits.
public const int KEY_SIZE = KEY_BITS / 8; //!< DVB CSA-2 control words size in bytes. public const int KEY_SIZE = KEY_BITS / 8; //!< DVB CSA-2 control words size in bytes.
public const int BLOCK_SIZE = 8; public const int BLOCK_SIZE = 8;
public const int MAX_NBLOCKS = (184 / 8);
public enum EntropyMode public enum EntropyMode
{ {
@ -101,7 +102,7 @@ namespace skyscraper8.Skyscraper.Security.Cryptography
return new Tuple<string, int, int>("DVB-CSA2", BLOCK_SIZE, KEY_SIZE); return new Tuple<string, int, int>("DVB-CSA2", BLOCK_SIZE, KEY_SIZE);
} }
protected bool SetKeyImpl(byte[] newKey) public bool SetKeyImpl(byte[] newKey)
{ {
// Only one possible key size. // Only one possible key size.
if (newKey.Length != KEY_SIZE) if (newKey.Length != KEY_SIZE)
@ -132,16 +133,134 @@ namespace skyscraper8.Skyscraper.Security.Cryptography
return true; return true;
} }
protected static bool EncryptImpl(Span<byte> plain, int plain_length, Span<byte> cipher, int cipher_maxsize, ref int cipher_length) protected bool EncryptImpl(Span<byte> input, int inputLength, Span<byte> output, int size, ref int retsize)
{
if (size < inputLength)
return false;
size = inputLength;
if (retsize != 0)
retsize = size;
if (input != output)
{
input.CopyTo(output);
}
Span<byte> data = output;
int nblocks = size / 8;
int rsize = size % 8;
if (data == null || nblocks > MAX_NBLOCKS || !_init)
return false;
if (size < 8)
return true;
DvbStreamCipher stream_ctx;
byte[] iblock = new byte[8];
byte[][] ib = new byte[MAX_NBLOCKS + 1][];
for (int i = 0; i < ib.Length; i++)
ib[i] = new byte[8];
byte[] ostream = new byte[8];
Array.Clear(ib[nblocks]);
for (int i = nblocks - 1; i >= 0; i--)
{
xor_8(iblock, data.Slice(8 * i), ib[i + 1]);
_block.Encipher(iblock, ib[i]);
}
memcpy_8(data, ib[0]);
stream_ctx = _stream;
stream_ctx.Cipher(ib[0], ostream);
for (int i = 1; i < nblocks; i++)
{
stream_ctx.Cipher(null, ostream);
xor_8(data.Slice(8 * i), ib[i], ostream);
}
if (rsize > 0)
{
stream_ctx.Cipher(null, ostream);
for (int i = 0; i < rsize; i++)
{
data[8 * nblocks + i] ^= ostream[i];
}
}
return true;
}
public bool DecryptImpl(Span<byte> input, int inputLength, Span<byte> output, int size, ref int retsize)
{
if (size < inputLength)
return false;
size = inputLength;
if (retsize != 0)
retsize = size;
if (input != output)
input.CopyTo(output);
Span<byte> data = output;
int nblocks = size / 8;
int rsize = size % 8;
if (data == null || nblocks > MAX_NBLOCKS || !_init)
return false;
if (size < 8)
return true;
DvbStreamCipher stream_ctx;
byte[] ostream = new byte[8];
byte[] ib = new byte[8];
byte[] oblock = new byte[8];
stream_ctx = _stream;
stream_ctx.Cipher(data, ib);
for (int i = 1; i < nblocks; i++)
{
_block.Decipher(ib, oblock);
stream_ctx.Cipher(null, ostream);
xor_8(ib, data.Slice(8 * i), ostream);
xor_8(data.Slice(8 * (i - 1)), ib, oblock);
}
_block.Decipher(ib, data.Slice(8 * (nblocks - 1)));
if (rsize > 0)
{
stream_ctx.Cipher(null, ostream);
for (int i = 0; i < rsize; i++)
{
data[8 * nblocks + 1] ^= ostream[i];
}
}
return true;
}
private void xor_8(Span<byte> iblock, byte[] slice, byte[] ostream)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
protected bool DecryptImpl(Span<byte> cipher, int cipher_length, Span<byte> plain, int plain_maxsize, ref int plain_length) private void memcpy_8(Span<byte> data, byte[] bytes)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
private void xor_8(byte[] res, Span<byte> a, byte[] b)
{
res[0] = (byte)(a[0] ^ b[0]);
}
private class DvbBlockCipher private class DvbBlockCipher
{ {
private readonly byte[] key_perm = { private readonly byte[] key_perm = {
@ -235,6 +354,8 @@ namespace skyscraper8.Skyscraper.Security.Cryptography
private int[] _kk; //57 items private int[] _kk; //57 items
public void Init(Span<byte> key) public void Init(Span<byte> key)
{ {
_kk = new int[57];
int i, j, k; int i, j, k;
int[] bit = new int[64]; int[] bit = new int[64];
int[] newbit = new int[64]; int[] newbit = new int[64];
@ -394,6 +515,9 @@ namespace skyscraper8.Skyscraper.Security.Cryptography
public void Init(Span<byte> key) public void Init(Span<byte> key)
{ {
A = new int[11];
B = new int[11];
A[1] = (key[0] >> 4) & 0x0F; A[1] = (key[0] >> 4) & 0x0F;
A[2] = (key[0] >> 0) & 0x0F; A[2] = (key[0] >> 0) & 0x0F;
A[3] = (key[1] >> 4) & 0x0F; A[3] = (key[1] >> 4) & 0x0F;