Skip to content

Instantly share code, notes, and snippets.

@sr229
Created February 25, 2026 20:08
Show Gist options
  • Select an option

  • Save sr229/cb1a571d4f93f52a60cf9ccb5a16e32d to your computer and use it in GitHub Desktop.

Select an option

Save sr229/cb1a571d4f93f52a60cf9ccb5a16e32d to your computer and use it in GitHub Desktop.
A modernised version of Pldare/aes.cs for .NET 6.0 with additional documentation Original: https://gist.github.com/Pldare/ebf704c752a8d77ff9603d4adfe54083
using System.Security.Cryptography;
using System.IO.Compression;
namespace Vroid
{
class VroidDecode
{
public static void Main(string[] args)
{
// read the file from arguments, then get the binary representation
var fs = new FileStream(args[0], FileMode.Open);
var bs = new BinaryReader(fs);
// VRoid Hub Encrypted VRMs usually have a the following data structure:
// * The first 16 bytes is the Initialization Vector
// * 32 bytes is the actual AES key
// * The cipher is AES-CBC
// * Then the rest of the VRM is Gzipped compressed for web transfer.
//
// with this in mind, we now try to access those specific bits first.
int bufferSize = ((int)fs.Length)-48;
using Aes aes = Aes.Create();
aes.IV = bs.ReadBytes(16);
aes.Key = bs.ReadBytes(32);
aes.Mode = CipherMode.CBC;
// now everything is set, we now try to decrypt it!
var decrypted = aes.CreateDecryptor().TransformFinalBlock(bs.ReadBytes(bufferSize), 0, bufferSize);
// of course now we got the decrypted part, we still have to deal with the Gzip compression.
var decryptedStream = new MemoryStream(decrypted);
var decompressedStream = new GZipStream(decryptedStream, CompressionMode.Decompress);
var finalStream = new FileStream(args[0] + ".dec", FileMode.OpenOrCreate, FileAccess.Write);
int data;
while ((data = decompressedStream.ReadByte()) != -1)
{
finalStream.WriteByte((byte)data);
}
Console.WriteLine($"Done! Saved as {args[0]}.dec");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment