Skip to content

Instantly share code, notes, and snippets.

@Nenkai
Created January 16, 2026 17:22
Show Gist options
  • Select an option

  • Save Nenkai/b30f15044d4292459218875281ce522a to your computer and use it in GitHub Desktop.

Select an option

Save Nenkai/b30f15044d4292459218875281ce522a to your computer and use it in GitHub Desktop.
AEWFFSaveEncDec
///////////////////////////////////////////////////////
// AEWFFSaveEncDec by Nenkai
// Requires: .NET 10.0
// Extract raw/raw sub data from sav files (i.e UGCWrestler_2.sav) first, using GvasViewer or something else
// Usage: dotnet run AEWFFEncDec.cs <input file path, encrypted or decrypted>
// The decrypted output is another save file
///////////////////////////////////////////////////////
// SPDX-FileCopyrightText: Copyright 2026 Nenkai
// SPDX-License-Identifier: MIT
using System.Buffers.Binary;
using System.Security.Cryptography;
using System.Text;
Console.WriteLine("-----------------------------------------");
Console.WriteLine($"- AEWFFSaveEncDec by Nenkai");
Console.WriteLine("-----------------------------------------");
Console.WriteLine("- https://github.com/Nenkai");
Console.WriteLine("- https://twitter.com/Nenkaai");
Console.WriteLine("-----------------------------------------");
Console.WriteLine("");
if (args.Length == 0 || !File.Exists(args[0]))
{
Console.WriteLine("Usage: <input file path, encrypted or decrypted>");
return;
}
Console.WriteLine($"Input: {args[0]}");
try
{
byte[] input = File.ReadAllBytes(args[0]);
string fullPath = Path.GetFullPath(args[0]);
uint length = BinaryPrimitives.ReadUInt32LittleEndian(input);
// ELGameServerParam->SaveDataEncryptKey
// https://github.com/peek6/AewFFCustomUProj/blob/2eef5e9c86cb1982eb3ea57ce0a6b43729a9e2a7/Source/ABP_200508/Private/ELGameServerParam.cpp#L25
const string KeyStr = "hSmG!+h2Sp.NZ*b~,X.BEy,5Kr3++UFS9.iX7";
byte[] Key = Encoding.UTF8.GetBytes(KeyStr).AsSpan(0, 32).ToArray();
using Aes aes = Aes.Create();
aes.Key = Key;
if (input.Length >= 4 && length == input.Length - 4)
{
Console.WriteLine("Assuming encrypted, decrypting");
Span<byte> encrypted = input.AsSpan(0x04);
aes.DecryptEcb(encrypted, encrypted, PaddingMode.None);
string newPath = Path.Combine(Path.GetDirectoryName(fullPath), $"{Path.GetFileNameWithoutExtension(fullPath)}_dec" + Path.GetExtension(fullPath));
File.WriteAllBytes(newPath, encrypted);
Console.WriteLine($"Decrypted to {newPath}");
}
else
{
Console.WriteLine("Assuming decrypted, encrypting");
aes.EncryptEcb(input, input, PaddingMode.None);
byte[] newBuffer = new byte[4 + input.Length];
BinaryPrimitives.WriteInt32LittleEndian(newBuffer, input.Length);
input.AsSpan().CopyTo(newBuffer.AsSpan(0x04));
string newPath = Path.Combine(Path.GetDirectoryName(fullPath), $"{Path.GetFileNameWithoutExtension(fullPath)}_enc" + Path.GetExtension(fullPath));
File.WriteAllBytes(newPath, newBuffer);
Console.WriteLine($"Encrypted to {newPath}");
}
}
catch (Exception e)
{
Console.WriteLine($"Errored: {e.Message}");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment