Voici donc mes objectifs:CryptoStream me force à fuir les données sensibles dans la RAM
- décryptez un
byte[]
dans un épinglébyte[]
tampon. - Je ne veux pas que le texte brut existe ailleurs en mémoire, en dehors de ce
byte[]
épinglé, que je contrôle.
Comment puis-je faire cela en C#? J'ai utilisé naïvement la classe CryptoStream
. Mais cela exige moi pour lui donner un flux de sortie. Je dois. Alors je suis allé de l'avant et lui ai donné un MemoryStream
. J'ai fait un peu de reniflage en mémoire, en utilisant la fenêtre de débogage mémoire. Je crois que j'ai trouvé que MemoryStream
a une copie (pour le tampon?) De tout ce qui sort du CryptoStream
. Alors maintenant, le texte brut est à la fois dans mon byte[]
épinglé, et dans cette autre partie de la mémoire qui peut être copiée au hasard par le CLR, et sur laquelle je n'ai aucun contrôle.
Voici le code que j'ai utilisé. Je suppose pas ici pour la simplicité concurrency:
public class ExampleCode
{
private SymmetricAlgorithm algorithm;
private ICryptoTransform decryptor;
public ExampleCode(byte[] key, byte[] iv) // c'tor
{
algorithm = new RijndaelManaged();
algorithm.Key = key;
algorithm.IV = iv;
decryptor = algorithm.CreateDecryptor();
}
private long DecryptToPinnedArray(byte[] src, byte[] pinnedDst)
{
long bytesWritten = 0;
using (var ms = new MemoryStream(pinnedDst, writable: true))
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
{
cs.Write(src, 0, src.Length);
cs.FlushFinalBlock();
ms.Flush();
bytesWritten = ms.Position;
return bytesWritten;
}
}
}
Comment puis-je éviter cette deuxième copie des données sensibles d'être jamais créé? Devrais-je oublier CryptoStream
et utiliser quelque chose de plus bas niveau? Existe-t-il une meilleure pratique pour des problèmes comme celui-ci?
EDIT: Peeking avec un réflecteur, ce que je pense qui se passe:
CryptoStream.Write()
:
- cipher_data - = copier - =>_InputBuffer (un
CryptoStream
interne non épinglébyte[]
). - _InputBuffer - = transformer - =>_OutputBuffer (a désépinglé interne
CryptoStream
byte[]
). - _OutputBuffer - = écriture - =>
MemoryStream
Si elle doit (et peut) transformer plus d'un bloc à la fois, il utilisera un désépinglé temporaire de plus grande envergure locale byte[]
(multiBlockArray) pour essayer de transformer tous les blocs en une seule fois (au lieu de _OutputBuffer). Il écrit multiBlockArray dans le flux. Il perd ensuite la référence à ce tableau, et ne tente même pas de le désinfecter. Bien sûr, ce n'est pas épinglé de toute façon.
CryptoStream.FlushFinalBlock()
& CryptoStream.Dispose()
:
Tous deux Array.Clear
le _OutputBuffer. C'est mieux que rien, bien que _OutputBuffer ne soit pas épinglé, donc il peut encore potentiellement fuir les données en texte brut.
Je ne vois rien dans la classe [MemoryStream] (https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/io/memorystream.cs) qui ressemble à une * copie * de le tampon que vous fournissez dans le constructeur. –
Si ce n'est pas le 'MemoryStream' alors c'est peut-être le' decryptor', ou le 'CryptoStream' lui-même? J'ai ajouté des informations sur le 'decryptor' que j'ai utilisé pour la question. –