求AESCrypt-Android库的C#实现方案:适配空IV处理
在C#中复现AESCrypt-Android的加密行为(含空IV处理)
我特意翻了AESCrypt-Android的源码,找到了它的核心加密逻辑,帮你写了一套完全匹配的C#实现,解决你遇到的空IV问题——先说明下:AES-CBC模式要求IV必须是16字节,你说的“空IV”应该是指全0的16字节数组吧?下面是具体步骤和代码:
先搞懂AESCrypt-Android的关键细节
这个库的加密逻辑是固定的,最容易踩坑的几个点:
- 加密模式:
AES/CBC/PKCS7Padding - 密钥派生:用
PBKDF2WithHmacSHA1,迭代1000次,生成256位密钥,盐是密码本身的UTF-8字节数组(很多其他库用随机盐,这是结果不匹配的核心原因!) - IV处理:默认生成随机16字节IV,然后把IV拼在密文最前面;如果自定义IV(包括全0的),必须是16字节,否则会抛异常
C# 实现代码
下面的代码完全对齐Android库的逻辑,支持自定义全0IV的场景:
核心加密解密类
using System; using System.IO; using System.Security.Cryptography; using System.Text; public class AESCryptAndroidPort { private const int IterationCount = 1000; private const int KeyBitSize = 256; private const int IvByteSize = 16; // AES块大小固定16字节,CBC模式IV必须和块大小一致 // 派生密钥,完全匹配Android的PBKDF2WithHmacSHA1逻辑 private static byte[] GetDerivedKey(string password) { byte[] passwordUtf8 = Encoding.UTF8.GetBytes(password); // 注意:盐就是密码的UTF8字节,这是AESCrypt-Android的特殊处理 using var pbkdf2 = new Rfc2898DeriveBytes(password, passwordUtf8, IterationCount, HashAlgorithmName.SHA1); return pbkdf2.GetBytes(KeyBitSize / 8); } /// <summary> /// 加密数据,和AESCrypt-Android输出完全一致 /// </summary> /// <param name="password">加密密码</param> /// <param name="plainData">明文字节数组</param> /// <param name="customIv">自定义IV(传null则生成随机IV,传全0数组就是你说的"空IV")</param> /// <returns>加密结果:IV + 密文(和Android库格式一致)</returns> public static byte[] Encrypt(string password, byte[] plainData, byte[] customIv = null) { byte[] key = GetDerivedKey(password); byte[] iv = customIv ?? GenerateRandomIv(); if (iv.Length != IvByteSize) { throw new ArgumentException($"IV必须是{IvByteSize}字节长度", nameof(customIv)); } using var aes = Aes.Create(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = key; aes.IV = iv; using var ms = new MemoryStream(); // 先写IV,和Android库一致,IV放在密文最前面 ms.Write(iv, 0, iv.Length); using var cryptoStream = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write); cryptoStream.Write(plainData, 0, plainData.Length); cryptoStream.FlushFinalBlock(); return ms.ToArray(); } /// <summary> /// 解密数据,支持Android库加密的结果 /// </summary> /// <param name="password">解密密码</param> /// <param name="encryptedData">加密后的数据(IV + 密文)</param> /// <returns>明文字节数组</returns> public static byte[] Decrypt(string password, byte[] encryptedData) { if (encryptedData.Length < IvByteSize) { throw new ArgumentException("加密数据长度不够,无法提取IV", nameof(encryptedData)); } byte[] key = GetDerivedKey(password); // 提取前16字节作为IV byte[] iv = new byte[IvByteSize]; Array.Copy(encryptedData, 0, iv, 0, IvByteSize); // 剩下的是密文 byte[] ciphertext = new byte[encryptedData.Length - IvByteSize]; Array.Copy(encryptedData, IvByteSize, ciphertext, 0, ciphertext.Length); using var aes = Aes.Create(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = key; aes.IV = iv; using var ms = new MemoryStream(); using var cryptoStream = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write); cryptoStream.Write(ciphertext, 0, ciphertext.Length); cryptoStream.FlushFinalBlock(); return ms.ToArray(); } // 生成随机IV,和Android库默认行为一致 private static byte[] GenerateRandomIv() { byte[] iv = new byte[IvByteSize]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(iv); return iv; } }
全0IV场景的使用示例
如果你在Android端用的是全0的IV,直接这么调用就行:
// 模拟你说的"空IV"——16个0字节的数组 byte[] emptyIv = new byte[16]; string yourPassword = "yourSecretPassword"; byte[] plainTextBytes = Encoding.UTF8.GetBytes("Hello from C#!"); // 加密 byte[] encrypted = AESCryptAndroidPort.Encrypt(yourPassword, plainTextBytes, emptyIv); // 解密验证 byte[] decryptedBytes = AESCryptAndroidPort.Decrypt(yourPassword, encrypted); string decryptedText = Encoding.UTF8.GetString(decryptedBytes); // decryptedText应该等于"Hello from C#!"
避坑提醒
- 盐的处理:千万别忘了AESCrypt-Android用密码本身当盐,这和大多数标准加密实现不一样,是最容易导致结果不匹配的点。
- IV格式:Android库会把IV直接拼在密文前面,解密时必须先提取前16字节,不能直接用整个加密数据当密文。
- 填充模式:必须用
PKCS7Padding,C#里的PaddingMode.PKCS7和Java的完全兼容。 - 密钥长度:默认是256位,现代.NET版本默认支持AES-256,不用额外配置。
内容的提问来源于stack exchange,提问作者Pecana
相关产品推荐
相关产品推荐

