From 8559368a138498fbe434b0505a42bae9d0217a77 Mon Sep 17 00:00:00 2001 From: Rebecca Wallander Date: Sat, 29 Jul 2023 23:50:37 +0200 Subject: [PATCH] Decrypt CSS images on conversion --- Aaru.Core/Devices/Dumping/Sbc/Data.cs | 4 +- Aaru.Core/Devices/Dumping/Sbc/Error.cs | 2 +- Aaru.Decryption | 2 +- Aaru.Images/AaruFormat/Read.cs | 3 - Aaru/Commands/Image/Convert.cs | 123 ++++++++++++++++++++++++- 5 files changed, 126 insertions(+), 8 deletions(-) diff --git a/Aaru.Core/Devices/Dumping/Sbc/Data.cs b/Aaru.Core/Devices/Dumping/Sbc/Data.cs index ad09b5000..624166adb 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Data.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Data.cs @@ -181,7 +181,7 @@ void ReadSbcData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, Du outputFormat.WriteSectorTag(titleKey.Value.Key, i + j, SectorTagType.DvdTitleKey); _resume.MissingTitleKeys.Remove(i + j); - CSS.DecryptTitleKey(0, discKey, titleKey.Value.Key, out tmpBuf); + CSS.DecryptTitleKey( discKey, titleKey.Value.Key, out tmpBuf); outputFormat.WriteSectorTag(tmpBuf, i + j, SectorTagType.DvdTitleKeyDecrypted); } @@ -203,7 +203,7 @@ void ReadSbcData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, Du ErrorMessage?. Invoke(string.Format(Localization.Core.Error_retrieving_title_key_for_sector_0, i)); else - buffer = CSS.DecryptSector(buffer, cmi, titleKey, blocksToRead, blockSize); + buffer = CSS.DecryptSector(buffer, titleKey, cmi, blocksToRead, blockSize); } } } diff --git a/Aaru.Core/Devices/Dumping/Sbc/Error.cs b/Aaru.Core/Devices/Dumping/Sbc/Error.cs index 3a10e4cac..7b5db44c5 100644 --- a/Aaru.Core/Devices/Dumping/Sbc/Error.cs +++ b/Aaru.Core/Devices/Dumping/Sbc/Error.cs @@ -409,7 +409,7 @@ void RetryTitleKeys(DVDDecryption dvdDecrypt, byte[] discKey, ref double totalDu if(discKey != null) { - CSS.DecryptTitleKey(0, discKey, titleKey.Value.Key, out buffer); + CSS.DecryptTitleKey(discKey, titleKey.Value.Key, out buffer); outputFormat.WriteSectorTag(buffer, missingKey, SectorTagType.DvdTitleKeyDecrypted); } diff --git a/Aaru.Decryption b/Aaru.Decryption index bc4497d67..00f15ee67 160000 --- a/Aaru.Decryption +++ b/Aaru.Decryption @@ -1 +1 @@ -Subproject commit bc4497d6769d9925c794d3b520a4aba886cd2255 +Subproject commit 00f15ee67ddb9089ff74c3e117dc5006f9635247 diff --git a/Aaru.Images/AaruFormat/Read.cs b/Aaru.Images/AaruFormat/Read.cs index c2fb17742..d12abea14 100644 --- a/Aaru.Images/AaruFormat/Read.cs +++ b/Aaru.Images/AaruFormat/Read.cs @@ -1759,9 +1759,6 @@ public ErrorNumber ReadSectorsTag(ulong sectorAddress, uint length, SectorTagTyp trk.EndSector == 0) return ErrorNumber.SectorNotFound; - if(trk.Type == TrackType.Data) - return ErrorNumber.NotSupported; - switch(tag) { case SectorTagType.CdSectorEcc: diff --git a/Aaru/Commands/Image/Convert.cs b/Aaru/Commands/Image/Convert.cs index cdb83645b..95bf05760 100644 --- a/Aaru/Commands/Image/Convert.cs +++ b/Aaru/Commands/Image/Convert.cs @@ -44,9 +44,11 @@ using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Metadata; +using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Core; using Aaru.Core.Media; +using Aaru.Decryption.DVD; using Aaru.Devices; using Aaru.Localization; using Schemas; @@ -54,6 +56,7 @@ using File = System.IO.File; using ImageInfo = Aaru.CommonTypes.Structs.ImageInfo; using MediaType = Aaru.CommonTypes.MediaType; +using Partition = Aaru.CommonTypes.Partition; using TapeFile = Aaru.CommonTypes.Structs.TapeFile; using TapePartition = Aaru.CommonTypes.Structs.TapePartition; using Track = Aaru.CommonTypes.Structs.Track; @@ -143,6 +146,11 @@ public ConvertImageCommand() : base("convert", UI.Image_Convert_Command_Descript { "--generate-subchannels" }, () => false, UI.Generates_subchannels_help)); + + Add(new Option(new[] + { + "--decrypt" + }, () => false, "Try to decrypt encrypted sectors.")); Add(new Option(new[] { @@ -173,7 +181,7 @@ public static int Invoke(bool verbose, bool debug, string cicmXml, string commen int mediaSequence, string mediaSerialNumber, string mediaTitle, string outputPath, string options, string resumeFile, string format, string geometry, bool fixSubchannelPosition, bool fixSubchannel, bool fixSubchannelCrc, - bool generateSubchannels, string aaruMetadata) + bool generateSubchannels, bool decrypt, string aaruMetadata) { MainClass.PrintCopyright(); @@ -239,6 +247,7 @@ public static int Invoke(bool verbose, bool debug, string cicmXml, string commen AaruConsole.DebugWriteLine("Image convert command", "--fix-subchannel={0}", fixSubchannel); AaruConsole.DebugWriteLine("Image convert command", "--fix-subchannel-crc={0}", fixSubchannelCrc); AaruConsole.DebugWriteLine("Image convert command", "--generate-subchannels={0}", generateSubchannels); + AaruConsole.DebugWriteLine("Image convert command", "--decrypt={0}", decrypt); AaruConsole.DebugWriteLine("Image convert command", "--aaru-metadata={0}", aaruMetadata); Dictionary parsedOptions = Core.Options.Parse(options); @@ -765,6 +774,9 @@ outputFormat is IWritableOpticalImage outputOptical && } ErrorNumber errno = ErrorNumber.NoError; + + if(decrypt) + AaruConsole.WriteLine("Decrypting encrypted sectors."); AnsiConsole.Progress().AutoClear(true).HideCompleted(true). Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()). @@ -772,6 +784,7 @@ outputFormat is IWritableOpticalImage outputOptical && { ProgressTask discTask = ctx.AddTask(UI.Converting_disc); discTask.MaxValue = inputOptical.Tracks.Count; + byte[] generatedTitleKeys = null; foreach(Track track in inputOptical.Tracks) { @@ -861,6 +874,114 @@ outputFormat is IWritableOpticalImage outputOptical && : inputOptical.ReadSectors(doneSectors + track.StartSector, sectorsToDo, out sector); + // TODO: Move to generic place when anything but CSS DVDs can be decrypted + if(inputOptical.Info.MediaType is MediaType.DVDROM or MediaType.DVDR + or MediaType.DVDRDL or MediaType.DVDPR or MediaType.DVDPRDL && decrypt) + { + // Only sectors which are MPEG packets can be encrypted. + if(MPEG.ContainsMpegPackets(sector, sectorsToDo)) + { + byte[] cmi, titleKey; + + if(sectorsToDo == 1) + { + if(inputOptical.ReadSectorTag(doneSectors + track.StartSector, + SectorTagType.DvdCmi, out cmi) == ErrorNumber.NoError && + inputOptical.ReadSectorTag(doneSectors + track.StartSector, + SectorTagType.DvdTitleKeyDecrypted, out titleKey) == + ErrorNumber.NoError) + { + sector = CSS.DecryptSector(sector, titleKey, cmi); + } + else + { + if(generatedTitleKeys == null) + { + List partitions = + Aaru.Core.Partitions.GetAll(inputOptical); + + partitions = partitions.FindAll(p => + { + Core.Filesystems.Identify(inputOptical, + out List idPlugins, p); + + return idPlugins.Contains("iso9660 filesystem"); + }); + + if(plugins.ReadOnlyFilesystems. + TryGetValue("iso9660 filesystem", + out Type pluginType)) + { + generatedTitleKeys = + CSS.GenerateTitleKeys(inputOptical, partitions, + trackSectors, pluginType); + } + } + + if(generatedTitleKeys != null) + { + sector = + CSS.DecryptSector(sector, + generatedTitleKeys. + Skip((int)(5 * (doneSectors + + track. + StartSector))). + Take(5).ToArray(), + null); + } + } + } + else + { + if(inputOptical.ReadSectorsTag(doneSectors + track.StartSector, + sectorsToDo, SectorTagType.DvdCmi, out cmi) == + ErrorNumber.NoError && + inputOptical.ReadSectorsTag(doneSectors + track.StartSector, + sectorsToDo, SectorTagType.DvdTitleKeyDecrypted, + out titleKey) == ErrorNumber.NoError) + { + sector = CSS.DecryptSector(sector, titleKey, cmi, sectorsToDo); + } + else + { + if(generatedTitleKeys == null) + { + List partitions = + Aaru.Core.Partitions.GetAll(inputOptical); + + partitions = partitions.FindAll(p => + { + Core.Filesystems.Identify(inputOptical, + out List idPlugins, p); + + return idPlugins.Contains("iso9660 filesystem"); + }); + + if(plugins.ReadOnlyFilesystems. + TryGetValue("iso9660 filesystem", + out Type pluginType)) + { + generatedTitleKeys = CSS.GenerateTitleKeys(inputOptical, partitions, + trackSectors, pluginType); + } + } + + if(generatedTitleKeys != null) + { + sector = + CSS.DecryptSector(sector, + generatedTitleKeys. + Skip((int)(5 * (doneSectors + + track. + StartSector))). + Take((int)(5 * sectorsToDo)).ToArray(), + null, sectorsToDo); + } + } + } + } + } + if(errno == ErrorNumber.NoError) result = sectorsToDo == 1 ? outputOptical.WriteSector(sector,