ITI 是不是存在相当于“Memset”或“SecureZeroMemory”的 C#
Posted
技术标签:
【中文标题】ITI 是不是存在相当于“Memset”或“SecureZeroMemory”的 C#【英文标题】:ITIs there a C# equivalent of `Memset` or `SecureZeroMemory`ITI 是否存在相当于“Memset”或“SecureZeroMemory”的 C# 【发布时间】:2019-09-26 22:04:18 【问题描述】:我正在创建 Unity 游戏,因此我需要为我的保存文件和其他敏感数据提供一些安全措施。为此,我创建了一些使用内置 AES 和 RSA 加密方法的函数。但是,它们应该具有某种“内存清除”功能,可以自动将不再使用的任何内存归零。问题是,我在 c# 中找不到任何等价物。我能找到的最接近的是
[DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]
public unsafe static extern bool ZeroMemory(byte* destination, int length);
但我不知道如何使用它(以前从未使用过指针)。任何帮助将不胜感激。
编辑:添加代码
请注意,我是从我的 Main()
程序
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using Encryption_test;
class OurCodeWorld
public static int _BlockSize = 128,
_KeySize = 256,
_Iterations = 50000;
public static PaddingMode _PaddingMode = PaddingMode.PKCS7;
public static CipherMode _CipherMode = CipherMode.CBC;
// Call this function to remove the key from memory after use for security
[DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]
public unsafe static extern bool ZeroMemory(byte* destination, int length);
/// <summary>
/// Creates a random salt that will be used to encrypt your file. This method is required on FileEncrypt.
/// </summary>
/// <returns></returns>
public static byte[] GenerateRandomSalt(int size = 32)
byte[] data = new byte[size];
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
for (int i = 0; i < size/6; i++)
// Fill the buffer with the generated data
rng.GetBytes(data);
return data;
/// <summary>
/// Encrypts a file from its path and a plain password.
/// </summary>
/// <param name="inputFile">The file to encrypt</param>
/// <param name="password">The key used to encrypt the file</param>
public static void FileEncrypt(string inputFile, string password)
//http://***.com/questions/27645527/aes-encryption-on-large-files
//generate random salt
byte[] salt = GenerateRandomSalt();
//create output file name
FileStream fsCrypt = new FileStream(inputFile + Program.encryptedExtension, FileMode.Create);
//convert password string to byte arrray
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);
//Set Rijndael symmetric encryption algorithm
RijndaelManaged AES = new RijndaelManaged
KeySize = _KeySize,
BlockSize = _BlockSize,
Padding = _PaddingMode
;
//http://***.com/questions/2659214/why-do-i-need-to-use-the-rfc2898derivebytes-class-in-net-instead-of-directly
//"What it does is repeatedly hash the user password along with the salt." High iteration counts.
var key = new Rfc2898DeriveBytes(passwordBytes, salt, _Iterations);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
//Cipher modes: http://security.stackexchange.com/questions/52665/which-is-the-best-cipher-mode-and-padding-mode-for-aes-encryption
AES.Mode = _CipherMode;
// write salt to the begining of the output file, so in this case can be random every time
fsCrypt.Write(salt, 0, salt.Length);
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
//create a buffer (1mb) so only this amount will allocate in the memory and not the whole file
byte[] buffer = new byte[1048576];
int read;
try
while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
//Application.DoEvents(); // -> for responsive GUI, using Task will be better!
cs.Write(buffer, 0, read);
// Close up
fsIn.Close();
catch (Exception ex)
Console.WriteLine("Error: " + ex.Message);
finally
cs.Close();
fsCrypt.Close();
/// <summary>
/// Decrypts an encrypted file with the FileEncrypt method through its path and the plain password.
/// </summary>
/// <param name="inputFile"></param>
/// <param name="outputFile"></param>
/// <param name="password"></param>
public static void FileDecrypt(string inputFile, string outputFile, string password, int saltLength = 32)
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[saltLength];
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
fsCrypt.Read(salt, 0, salt.Length);
RijndaelManaged AES = new RijndaelManaged
KeySize = _KeySize,
BlockSize = _BlockSize
;
var key = new Rfc2898DeriveBytes(passwordBytes, salt, _Iterations);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = _PaddingMode;
AES.Mode = _CipherMode;
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile, FileMode.Create);
int read;
byte[] buffer = new byte[1048576];
try
while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
//Application.DoEvents();
fsOut.Write(buffer, 0, read);
catch (CryptographicException ex_CryptographicException)
Console.WriteLine("CryptographicException error: " + ex_CryptographicException.Message);
catch (Exception ex)
Console.WriteLine("Error: " + ex.Message);
try
cs.Close();
catch (Exception ex)
Console.WriteLine("Error by closing CryptoStream: " + ex.Message);
finally
fsOut.Close();
fsCrypt.Close();
【问题讨论】:
如果你使用的是string
,你不能开箱即用(因为它们是不可变的),如果你使用的是arrays您可以使用for
循环将它们设置为零,或者您可以使用指针 或fixed
和unsafe
,或其他非托管内存。问题是我们看不到你的代码来给你建议
@TheGeneral 如果它是一个数组,我会使用Array.Clear,它甚至可以在内部使用 memset。
@ckuri 当然可以
@TheGeneral @ckuri 它应该在Main()
函数的开头,但我现在将它拆分为其他几个函数。如果我想在函数中使用它,我该如何使用它。同时添加代码
【参考方案1】:
我在这里回答我自己的问题,请随时添加。
ZeroMemory
不是 C# 方法,它是存储在 Windows dll Kernel32.dll
中的非托管(可能是 C/C++)方法,在低级代码领域称为 RtlZeroMemory
。这就是extern
修饰符和DllImport
属性的作用;他们告诉 .Net 我想从.dll
中获取一个方法并使用它。
从技术上讲,有一个解决方案 - 只需使用这样的指针(但我不确定这与原始指针有多相似):
public static unsafe void ZeroMemory(byte* ptr, int length)
//Loop to cover all the bytes
for (int i = 0; i < length; i++)
//Set the byte at the index of (start + i) to 0
*(ptr + i) = 0;
我的问题最初源于对我在做什么缺乏了解,所以我对所有事情都感到困惑(比如如何使用该方法),这就是我发布问题的原因。我试图将密钥归零,以便无法从内存中读取它,这应该可以通过使用上面的代码来实现。
【讨论】:
以上是关于ITI 是不是存在相当于“Memset”或“SecureZeroMemory”的 C#的主要内容,如果未能解决你的问题,请参考以下文章
snprintf() 是不是在内部调用 memset() 或类似的?