将AES文件解密程序从Java重写为C#

本文关键字:Java 重写 程序 AES 文件 解密 | 更新日期: 2023-09-27 18:32:16

我有一个与文件解密相关的特定问题。我在 Java 中找到了一个解密特定文件的程序(这是游戏中的游戏保存文件,您可以在此处找到该文件的示例:https://www.adrive.com/public/6DBShx/game.sii),我想将该程序重写为 C# - 这样我就可以将其集成到我用 C# 编写的完全不同的程序中。这是我第一次使用加密文件,所以我制作的程序不起作用,实际上我不确定如何调试它。我编写的程序具有固定的文件路径 - 这是临时解决方案。

原始Java程序:

package scsc;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Map;
import java.util.zip.InflaterInputStream;
/*
 * Published under the Do What the Fuck You Want to Public License (       http://www.wtfpl.net/ )
 */
public class ScsC {
private static byte[] AES_KEY = new byte[]{
        (byte) 0x2a, (byte) 0x5f, (byte) 0xcb, (byte) 0x17,
        (byte) 0x91, (byte) 0xd2, (byte) 0x2f, (byte) 0xb6,
        (byte) 0x02, (byte) 0x45, (byte) 0xb3, (byte) 0xd8,
        (byte) 0x36, (byte) 0x9e, (byte) 0xd0, (byte) 0xb2,
        (byte) 0xc2, (byte) 0x73, (byte) 0x71, (byte) 0x56,
        (byte) 0x3f, (byte) 0xbf, (byte) 0x1f, (byte) 0x3c,
        (byte) 0x9e, (byte) 0xdf, (byte) 0x6b, (byte) 0x11,
        (byte) 0x82, (byte) 0x5a, (byte) 0x5d, (byte) 0x0a,
};
public static void main(String[] args) throws Exception {
    if (args.length < 1) {
        System.out.println("ERROR: expecting at least one file.");
    } else {
        removeCryptographyRestrictions();
        for (String filename : args) {
            decrypt(filename);
        }
    }
}
private static void decrypt(String filename) throws Exception {
    File scsc = new File(filename);
    if (!scsc.isFile() || !scsc.canWrite()) {
        throw new IllegalArgumentException(filename + " is not a writable file.");
    }
    boolean encrypted = isEncrypted(scsc);
    if (!encrypted) {
        System.out.println(scsc + " does not seem to be encrypted.");
    } else {
        File decrypted = decrypt(scsc);
        Files.copy(decrypted.toPath(), scsc.toPath(), StandardCopyOption.REPLACE_EXISTING);
        System.out.println("decrypted: " + scsc);
    }
}
private static boolean isEncrypted(File file) throws Exception {
    byte[] header = new byte[4];
    FileInputStream fis = new FileInputStream(file);
    if (fis.read(header) != header.length) {
        throw new RuntimeException("could not read header of " + file);
    }
    fis.close();
    String headerAsString = new String(header, Charset.forName("UTF-8"));
    return "ScsC".equals(headerAsString);
}
private static File decrypt(File input) throws Exception {
    File out = File.createTempFile("scsc-", ".tmp");
    out.deleteOnExit();
    byte[] data = new byte[(int) (input.length())];
    FileInputStream fis = new FileInputStream(input);
    if (fis.read(data) != data.length) {
        throw new RuntimeException("Could not read " + input + " into memory");
    }
    fis.close();
    byte[] cipherText = new byte[data.length - 0x38];
    byte[] iv = new byte[0x10];
    System.arraycopy(data, 0x38, cipherText, 0, cipherText.length);
    System.arraycopy(data, 0x24, iv, 0, iv.length);
    byte[] decrypted = decrypt(cipherText, AES_KEY, iv);
    ByteArrayInputStream bis = new ByteArrayInputStream(decrypted);
    InflaterInputStream iis = new InflaterInputStream(bis);
    InputStreamReader ir = new InputStreamReader(iis);
    BufferedReader br = new BufferedReader(ir);
    FileOutputStream fos = new FileOutputStream(out);
    OutputStreamWriter osw = new OutputStreamWriter(fos);
    PrintWriter pw = new PrintWriter(osw);
    for (String line = br.readLine(); line != null; line = br.readLine()) {
        pw.println(line);
    }
    pw.close();
    br.close();
    return out;
}
private static byte[] decrypt(byte[] cipherText, byte[] keyBytes, byte[] iv) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
    cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
    return cipher.doFinal(cipherText);
}
private static void removeCryptographyRestrictions() throws Exception {
    // taken from http://stackoverflow.com/questions/1179672/unlimited-strength-jce-policy-files
    final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
    final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
    final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
    final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
    isRestrictedField.setAccessible(true);
    isRestrictedField.set(null, false);
    final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
    defaultPolicyField.setAccessible(true);
    final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
    final Field perms = cryptoPermissions.getDeclaredField("perms");
    perms.setAccessible(true);
    ((Map<?, ?>) perms.get(defaultPolicy)).clear();
    final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
    instance.setAccessible(true);
    defaultPolicy.add((Permission) instance.get(null));
}
}

我用 C# 生成的代码似乎可以工作,但输出不如预期......预期结果应该是可读的文件(链接: https://www.adrive.com/public/E3rsfv/game.sii_decrypted_by_java )

解密文件的前几行:

SiiNunit
{
economy : _nameless.0357.B5D0 {
 bank: _nameless.0371.CD48
 player: _nameless.0369.3070
 companies: 811
 companies[0]: company.volatile.trameri.esbjerg
 companies[1]: company.volatile.bcp.turku
 companies[2]: company.volatile.itcc.liege
 companies[3]: company.volatile.tree_et.geneve
 companies[4]: company.volatile.tree_et.arhus
 companies[5]: company.volatile.itcc.jonkoping
 companies[6]: company.volatile.kaarfor.poznan
 companies[7]: company.volatile.fcp.milano
 companies[8]: company.volatile.posped.swansea
 companies[9]: company.volatile.tradeaux.lille
 companies[10]: company.volatile.euroacres.osnabruck

由 C# 解密 - 我不能在这里放很多链接:(

前几行:

     xڬ�M�$������C��4fcm�o��#=-     ��rLV������̪[���<�8�J��F����t��C������:�>������>Ƿ_��Ƿ ��m��~|�9�T����ߦ?�����*[�����X��} ���=����S�������9��Q����?�����~����|���?? O���������ӳx�Y<<����uz�PoAw����w���������������~sz�� ������z|��Wf��ٜ�O�6�/�;I�m���[-����}�������c��T��| ��D��K�8S�ۯ�q�x�~�y�8lN_���)7�������ux��xг���@}l�����15} x�������c��#Ul�>>���͛|�T����>�q�����py�! ����X�'�tW����!��ow�w��۸c�Ə��^κ �ŗ�{�I�P���7���9<| ��O�}�������6_�ؾ=��}�����{RVħ�9��?��i�|A�awz#;���w�Km� %�3a�"~ݜ��9y4�����r�6����ގ_�/ �1<ݍqL����w�����=�l~���H'�y4J������(gU(k��m�S�S���es8��3m Ű,�M��_��~��w� ��S- ��Y|z�KP�P�����:ֆ������G�q��v�&�QLp6��C}<? �G5�cY�����q��)���q�D�|ڪε�i�����XI��>Ӕ_:c�
 ��~�<�1��h���=���{8m��G�8X��ٞҚB�6�Oۅ�Jy<�>����  ����b�Mu�l�v�W[u
�]�V'�����帗�Cv��H�C��9   ����t�e��V�������^�Cy�߁oIñ���r�����R΃��H���C{�����ӏ�m ���

以及在 C# 中创建此类:

public partial class Form1 : Form
    {
        string file_original;
        byte[] file_orig_bytes;
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            byte[] AES_KEY = new byte[]{
            (byte) 0x2a, (byte) 0x5f, (byte) 0xcb, (byte) 0x17,
            (byte) 0x91, (byte) 0xd2, (byte) 0x2f, (byte) 0xb6,
            (byte) 0x02, (byte) 0x45, (byte) 0xb3, (byte) 0xd8,
            (byte) 0x36, (byte) 0x9e, (byte) 0xd0, (byte) 0xb2,
            (byte) 0xc2, (byte) 0x73, (byte) 0x71, (byte) 0x56,
            (byte) 0x3f, (byte) 0xbf, (byte) 0x1f, (byte) 0x3c,
            (byte) 0x9e, (byte) 0xdf, (byte) 0x6b, (byte) 0x11,
            (byte) 0x82, (byte) 0x5a, (byte) 0x5d, (byte) 0x0a,
            };
            string path = "game.sii";
            load_file_to_memory(path);
            //decrypt_file(AES_KEY);
            byte[] iv = new byte[0x10];
            byte[] cipherText = new byte[file_orig_bytes.Length - 0x38];
            Array.Copy(file_orig_bytes, 0x38, cipherText, 0, cipherText.Length);
            Array.Copy(file_orig_bytes, 0x24, iv, 0, iv.Length);
            string new_file = DecryptStringFromBytes_Aes(cipherText, AES_KEY, iv);
            int a;
        }
        private void load_file_to_memory(string path)
        {
            file_original = File.ReadAllText(path);
            file_orig_bytes = File.ReadAllBytes(path);
            int i;
        }
        static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key
, byte[] IV)
        {
            // Check arguments.
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");
            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;
            // Create an Aes object
            // with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            return plaintext;
        }

对此有任何帮助吗?谢谢

将AES文件解密程序从Java重写为C#

这是我的版本,似乎效果很好。你上一段代码的问题是原始java版本中未加密的内容是用"InflaterInputStream"类制作的,在c#中,我在sharpziplib中找到了这个类。

public class Test2
{
    static string file_original;
    static byte[] file_orig_bytes;
    static void Main(string[] args)
    {
        byte[] AES_KEY = new byte[]{
            (byte) 0x2a, (byte) 0x5f, (byte) 0xcb, (byte) 0x17,
            (byte) 0x91, (byte) 0xd2, (byte) 0x2f, (byte) 0xb6,
            (byte) 0x02, (byte) 0x45, (byte) 0xb3, (byte) 0xd8,
            (byte) 0x36, (byte) 0x9e, (byte) 0xd0, (byte) 0xb2,
            (byte) 0xc2, (byte) 0x73, (byte) 0x71, (byte) 0x56,
            (byte) 0x3f, (byte) 0xbf, (byte) 0x1f, (byte) 0x3c,
            (byte) 0x9e, (byte) 0xdf, (byte) 0x6b, (byte) 0x11,
            (byte) 0x82, (byte) 0x5a, (byte) 0x5d, (byte) 0x0a,
            };
        string path = @"C:'temp_10'game.sii";
        load_file_to_memory(path);
        //decrypt_file(AES_KEY);
        byte[] iv = new byte[0x10];
        byte[] cipherText = new byte[file_orig_bytes.Length - 0x38];
        Array.Copy(file_orig_bytes, 0x38, cipherText, 0, cipherText.Length);
        Array.Copy(file_orig_bytes, 0x24, iv, 0, iv.Length);
        byte[] decoded_binary_content = AESDecrypt(cipherText, AES_KEY, iv);
        string decoded_string_content = "";
        using (MemoryStream ms = new MemoryStream(decoded_binary_content))
        using (ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream iis = new ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream(ms))
        using (StreamReader sr = new StreamReader(iis))
            decoded_string_content = sr.ReadToEnd();
    }
    private static void load_file_to_memory(string path)
    {
        file_original = File.ReadAllText(path);
        file_orig_bytes = File.ReadAllBytes(path);
    }
    //http://lamahashim.blogspot.it/2009/08/encyptiondecryption-in-c-and-java.html
    static byte[] AESDecrypt(byte[] encryptedData, byte[] keyBytes, byte[] iv)
    {
        RijndaelManaged rijndaelCipher = new RijndaelManaged();
        rijndaelCipher.Mode = CipherMode.CBC;
        rijndaelCipher.Padding = PaddingMode.None;
        rijndaelCipher.IV = iv;
        rijndaelCipher.KeySize = 0x80;
        rijndaelCipher.BlockSize = 0x80;
        rijndaelCipher.Key = keyBytes;
        rijndaelCipher.IV = iv;
        byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length);
        return plainText;
    }
}

我已经从代码中显示的网址中复制了解密功能

在对阅读 SII 文件产生了兴趣后,我在遇到相同的 Java 程序后偶然发现了这个堆栈问题,在 bdn02 的答案的帮助下,我启动并运行了一个应用程序并进行了一些更改。

此版本使用 System.IO.Compression 命名空间中的 DeflateStream 类,而不是 SharpZipLib,并跳过压缩内容的前两个字节,因为这些字节包含 zlib 规范 (RFC 1950) 的压缩信息和标志,而此代码使用 deflate 规范 (RFC 1951)。

将此答案发布给将来遇到此问题并且不想依赖SharpZipLib或任何第三方软件包的其他人。

class Program
{
    private static byte[] AES_Key = { 42, 95, 203, 23, 145, 210, 47, 182, 2, 69, 179, 216, 54, 158, 208, 178, 194, 115, 113, 86, 63, 191, 31, 60, 158, 223, 107, 17, 130, 90, 93, 10 };
    static void Main(string[] args)
    {
        // Get bytes of AES Key, read contents
        var contentsBytes = File.ReadAllBytes("profile.sii");
        // Create IV & Cipher test byte arrays
        var iv = new byte[0x10];
        var cipherText = new byte[contentsBytes.Length - 0x38];
        // Copy contents bytes to cipherText & IV arrays
        Array.Copy(contentsBytes, 56, cipherText, 0, cipherText.Length);
        Array.Copy(contentsBytes, 36, iv, 0, iv.Length);
        // Create AES Crypto Service Provider with our Key & Vector.
        var cryptoServiceProvider = new AesCryptoServiceProvider
        {
            Mode = CipherMode.CBC,
            Padding = PaddingMode.None,
            KeySize = 0x80,
            BlockSize = 0x80,
            Key = AES_Key,
            IV = iv
        };
        // Create decryptor and get plain text of encrypted contents.
        var decryptor = cryptoServiceProvider.CreateDecryptor();
        var plainText = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);
        string decompressedContents;
        // Load into Memory Stream and skip the first 2 bytes.
        // Use a Deflate stream to decompress the contents
        // Read the deflated contents via our StreamReader
        using (var memStream = new MemoryStream(plainText, 2, plainText.Length - 2))
        using (var iis = new DeflateStream(memStream, CompressionMode.Decompress))
        using (var streamReader = new StreamReader(iis))
        {
            decompressedContents = streamReader.ReadToEnd();
        }
    }
}