Skip to content

Commit

Permalink
v2.4
Browse files Browse the repository at this point in the history
  • Loading branch information
kingsznhone committed Jul 30, 2024
1 parent 96fdbdc commit 3f709f0
Show file tree
Hide file tree
Showing 53 changed files with 607 additions and 499 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<StartupObject>NCMDumpCLI</StartupObject>
<ApplicationIcon>NCMDump.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Version>2.3.0</Version>
<Version>2.4.0</Version>
<Platforms>x64</Platforms>
</PropertyGroup>

Expand All @@ -18,8 +17,10 @@
<Content Include="NCMDump.ico" />
</ItemGroup>



<ItemGroup>
<ProjectReference Include="..\NCMDumpCore\NCMDumpCore.csproj" />
<ProjectReference Include="..\NCMDump.Core\NCMDump.Core.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
File renamed without changes.
File renamed without changes.
77 changes: 77 additions & 0 deletions src/NCMDump.CLI/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using NCMDump.Core;

namespace NCMDump.CLI
{
public class Application
{
public static NCMDumper Dumper = new();

public static void Main(params string[] args)
{
int depth = 0;
if (args.Length == 0)
{
if (OperatingSystem.IsWindows())
{
Console.WriteLine("Drag [*.ncm] file or directory on exe to start...");
Console.WriteLine("./ncmdump.exe <file_or_dir1> [<file_or_dir2> ... <file_or_dirN>]");
}
if (OperatingSystem.IsLinux())
{
Console.WriteLine("./ncmdump <file_or_dir1> [<file_or_dir2> ... <file_or_dirN>]");
}
return;
}

try
{
foreach (string path in args)
{
if (new DirectoryInfo(path).Exists)
{
WalkThrough(new DirectoryInfo(path));
}
else if (new FileInfo(path).Exists)
{
Console.Write($"Dumping: {new FileInfo(path).FullName} ......");
if (Dumper.Convert(path)) Console.WriteLine("OK");
else Console.WriteLine("Fail");
Console.WriteLine();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

Console.Write("Press Enter to Exit...");
Console.ReadLine();
return;

void WalkThrough(DirectoryInfo dir)
{
depth++;
if (depth > 16)
{
depth--;
return;
}
Console.WriteLine("DIR: " + dir.FullName);
foreach (DirectoryInfo d in dir.GetDirectories())
{
WalkThrough(d);
}
foreach (FileInfo f in dir.EnumerateFiles("*.ncm"))
{
Console.Write($"Dumping: {f.FullName} ......");
if (Dumper.Convert(f.FullName)) Console.WriteLine("OK");
else Console.WriteLine("...Fail");
}

Console.WriteLine();
depth--;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->

<!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />

</application>
</compatibility>
Expand Down
File renamed without changes
21 changes: 21 additions & 0 deletions src/NCMDump.Core/IRC4_NCM_Stream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace NCMDump.Core
{
public interface IRC4_NCM_Stream : IDisposable
{
public bool CanRead { get; }
public bool CanSeek { get; }
public bool CanWrite { get; }
public long Length { get; }
public long Position { get; set; }

public long Seek(long offset, SeekOrigin origin);

public int Read(byte[] buffer, int offset, int count);

public int Read(Span<byte> buffer);

public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);

public ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace NCMDumpCore
namespace NCMDump.Core
{
public class MetaInfo
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<TargetFrameworks>net8.0;</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<VersionPrefix>2.3.0</VersionPrefix>
<VersionPrefix>2.4.0</VersionPrefix>
<Platforms>x64</Platforms>
</PropertyGroup>

Expand Down
34 changes: 17 additions & 17 deletions src/NCMDumpCore/NCMDumper.cs → src/NCMDump.Core/NCMDumper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
using System.Text.Json;
using TagLib;

namespace NCMDumpCore
namespace NCMDump.Core
{
public class NCMDumper
{
private readonly int vectorSize = Vector256<byte>.Count;
private readonly byte[] coreKey = [0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57];
private readonly byte[] metaKey = [0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28];
private static readonly byte[] coreKey = [0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57];
private static readonly byte[] metaKey = [0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28];

private bool VerifyHeader(ref MemoryStream ms)
{
Expand Down Expand Up @@ -53,7 +53,7 @@ private byte[] ReadRC4Key(ref MemoryStream ms)
{
aes.Mode = CipherMode.ECB;
aes.Key = coreKey;
var cleanText = aes.DecryptEcb(buffer.ToArray(), PaddingMode.PKCS7).ToArray()[17..];
var cleanText = aes.DecryptEcb(buffer, PaddingMode.PKCS7)[17..];
return cleanText;
}
}
Expand All @@ -80,23 +80,24 @@ private MetaInfo ReadMeta(ref MemoryStream ms)
buffer[i] ^= 0x63;
}

buffer = System.Convert.FromBase64String(Encoding.ASCII.GetString(buffer.ToArray()[22..]));
buffer = System.Convert.FromBase64String(Encoding.ASCII.GetString(buffer[22..]));

// decrypt meta data which is a json contains info of the song
using (Aes aes = Aes.Create())
{
aes.Mode = CipherMode.ECB;
aes.Key = metaKey;
var cleanText = aes.DecryptEcb(buffer.ToArray(), PaddingMode.PKCS7);
var MetaJsonString = Encoding.UTF8.GetString(cleanText[6..]);
var cleanText = aes.DecryptEcb(buffer, PaddingMode.PKCS7);
var MetaJsonString = Encoding.UTF8.GetString(cleanText.AsSpan(6));
JsonSerializerOptions option = new JsonSerializerOptions();
MetaInfo metainfo = JsonSerializer.Deserialize<MetaInfo>(MetaJsonString);
return metainfo;
}
}

private async Task<byte[]> ReadAudioData(MemoryStream ms, byte[] Key)
{
using (RC4_NCM_Stream rc4s = new(ms, Key))
using (IRC4_NCM_Stream rc4s = new RC4_NCM_Stream(ms, Key))
{
byte[] data = new byte[ms.Length - ms.Position];
Memory<byte> m_data = new(data);
Expand All @@ -105,41 +106,41 @@ private async Task<byte[]> ReadAudioData(MemoryStream ms, byte[] Key)
}
}

private void AddTag(string fileName, byte[]? ImgData, MetaInfo metainfo)
private async Task AddTag(string fileName, byte[]? ImgData, MetaInfo metainfo)
{
var tagfile = TagLib.File.Create(fileName);

//Use Embedded Picture
if (ImgData is not null)
{
var PicEmbedded = new Picture(new ByteVector(ImgData));
tagfile.Tag.Pictures = new Picture[] { PicEmbedded };
tagfile.Tag.Pictures = [PicEmbedded];
}
//Use Internet Picture
else if (metainfo.albumPic != "")
{
byte[]? NetImgData = FetchUrl(new Uri(metainfo.albumPic));
byte[]? NetImgData = await FetchUrl(new Uri(metainfo.albumPic));
if (NetImgData is not null)
{
var PicFromNet = new Picture(new ByteVector(NetImgData));
tagfile.Tag.Pictures = new Picture[] { PicFromNet };
tagfile.Tag.Pictures = [PicFromNet];
}
}

//Add more information
tagfile.Tag.Title = metainfo.musicName;
tagfile.Tag.Performers = metainfo.artist.Select(x => x[0]).ToArray();
tagfile.Tag.Album = metainfo.album;
tagfile.Tag.Subtitle = String.Join(@";", metainfo.alias);
tagfile.Tag.Subtitle = string.Join(@";", metainfo.alias);
tagfile.Save();
}

private byte[]? FetchUrl(Uri uri)
private async Task<byte[]?> FetchUrl(Uri uri)
{
HttpClient client = new();
try
{
var response = client.GetAsync(uri).Result;
var response = await client.GetAsync(uri);
Console.WriteLine(response.StatusCode);
if (response.StatusCode == HttpStatusCode.OK)
{
Expand Down Expand Up @@ -230,8 +231,7 @@ public async Task<bool> ConvertAsync(string path)
//Flush Audio Data to disk drive
string OutputPath = path[..path.LastIndexOf('.')];

string format = metainfo.format;
if (format is null or "") format = "mp3";
string format = metainfo.format ?? "mp3";
await System.IO.File.WriteAllBytesAsync($"{OutputPath}.{format}", AudioData);

//Add tag and cover
Expand Down
24 changes: 11 additions & 13 deletions src/NCMDumpCore/RC4_NCM.cs → src/NCMDump.Core/RC4_NCM.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace NCMDumpCore
namespace NCMDump.Core
{
public class RC4_NCM
{
Expand All @@ -19,12 +19,11 @@ public RC4_NCM(byte[] key)

public byte[] Encrypt(byte[] data)
{
Span<byte> span = new(data);
Encrypt(ref span);
return span.ToArray();
Encrypt(data.AsSpan());
return data;
}

public int Encrypt(ref Span<byte> data)
public int Encrypt(Span<byte> data)
{
for (int m = 0; m < data.Length; m++)
{
Expand All @@ -37,13 +36,7 @@ public int Encrypt(ref Span<byte> data)

public int Encrypt(Memory<byte> data)
{
for (int m = 0; m < data.Length; m++)
{
i = (i + 1) & 0xFF;
j = (i + Keybox[i]) & 0xFF;
data.Span[m] ^= Keybox[(Keybox[i] + Keybox[j]) & 0xFF];
}
return data.Length;
return Encrypt(data.Span);
}

public byte[] Decrypt(byte[] data)
Expand All @@ -53,7 +46,12 @@ public byte[] Decrypt(byte[] data)

public int Decrypt(Span<byte> data)
{
return Encrypt(ref data);
return Encrypt(data);
}

public int Decrypt(Memory<byte> data)
{
return Encrypt(data);
}
}
}
Loading

0 comments on commit 3f709f0

Please sign in to comment.