|
Fiches TechniqueEncryptage avec le Compact Framework
|
Implémentation |
Limitations |
Quelques liens utiles... |
Historique de révisions... |
Lors de nos développements de différentes applications pour PocketPC nous avons été confronté au besoin d'encrypter les données devant être sauvegardées. En effet, sa nature "nomade" rend le PocketPC plus sensible aux vols. Il ne faut donc pas que le vol du matériel soit agravé par un vol de données sensible.
En recherchant sur la toile, nous avons trouvé sur le site de Markus Hahn son implémentation de l'algorithme Blowfish de Bruce Schneier en c#. Afin de l'intégrer simplement dans nos applications, nous avons implémenté un objet Stream autour de son objet Blowfish.
Ne sachant pas a priori sur quel support nous aurions besoin de sérialiser les informations, nous avons considéré l'encryptage comme une adaptation de l'écriture dans un Stream.
namespace FlowGroup.Crypto { ... public class BlowfishStream : Stream { ... private System.IO.Stream mStream; /// <summary> /// Construct a BlowfishStream that adapt the /// "stream" parameter in order to encrypt/decrypt /// the data /// </summary> /// <param name="stream">inner stream</param> /// <param name="key">key for the encryption</param> /// <param name="mode">Read or Write</param> public BlowfishStream(Stream stream, byte[] key, BlowfishStreamMode mode) { ... mStream = stream; ... } ... } }
Pour que le même objet puisse fonctionner avec des flux crypté ou non, nous avons décidé d'ajouter une signature en début de flux. Dans le cas ou le flux n'est pas crypté, l'objet délègue tous ses traitements à l'objet flux passé en paramètre.
public class BlowfishStream : Stream { static private readonly byte[] signature = { 5, 11, 14, 22, 6, 17, 15, 192}; private System.IO.Stream mStream; ... private bool mIsEncrypted = false; private byte[] mBuffer; private int mCount = 0; private byte mOffset = 0; ... public BlowfishStream(Stream stream, byte[] key, BlowfishStreamMode mode) { ... mStream = stream; mBuffer = new byte[256]; mMode = mode; switch(mode) { case BlowfishStreamMode.Read: mCount = (byte)mStream.Read(mBuffer, 0, 8); mOffset = 0; if(mCount == 8) { mIsEncrypted = true; while(mCount > 0) { mCount--; if(mBuffer[mCount] != signature[mCount]) { mCount = 8; mIsEncrypted = false; break; } // if } } break; case BlowfishStreamMode.Write: mIsEncrypted = true; mStream.Write(signature, 0, 8); break; } } ... public override long Seek(long offset, System.IO.SeekOrigin origin) { if(mIsEncrypted) throw new System.NotSupportedException(); return mStream.Seek(offset, origin); } public override void SetLength(long value) { if(mIsEncrypted) throw new NotSupportedException(); mStream.SetLength(value); } public override bool CanRead { get { return mIsEncrypted ? (mMode == BlowfishStreamMode.Read) : mStream.CanRead; } } public override bool CanSeek { get { return mIsEncrypted ? false : mStream.CanSeek; } } public override bool CanWrite { get { return mIsEncrypted ? (mMode == BlowfishStreamMode.Write) : mStream.CanWrite; } } public override long Length { get { if(mIsEncrypted) throw new System.NotSupportedException(); return mStream.Length; } } public override long Position { get { if(mIsEncrypted) throw new System.NotSupportedException(); return mStream.Position; } set { if(mIsEncrypted) throw new System.NotSupportedException(); mStream.Position = value; } }
Comme l'algorithme de Blowfish fonctionne par blocs de 8 octets, nous devons utiliser un tampon avant d'écrire dans le Stream interne. Il ne reste plus qu'a écrire les fonctions de lecture, écriture et flush...
public override void Flush() { if(!mIsEncrypted) { } else if(mMode == BlowfishStreamMode.Write) { if(mCount > 0) { int bound = ((mCount % 8) == 0) ? mCount : (((mCount / 8) + 1) * 8); mBlowfish.Encrypt(mBuffer, mBuffer, 0, 0, bound); mStream.WriteByte((byte)(mCount - 1)); mStream.Write(mBuffer, 0, bound); mCount = 0; mOffset = 0; } } mStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { if(mIsEncrypted) { int totalRead = 0; int read = 0; int bound; // while data are required, fill the internal buffer while(count > 0) { if(mCount == 0) { int nRead = 0; read = mStream.ReadByte(); if(read == -1) break; // the stream is empty mCount = read + 1; mOffset = 0; bound = ((mCount % 8) == 0) ? mCount : (((mCount / 8) + 1) * 8); read = mStream.Read(mBuffer, mOffset, bound); nRead += read; if(bound != read) { int nMaxCount = 256; while(nRead < bound) { read = mStream.Read(mBuffer, mOffset+nRead, bound-nRead); nRead += read; nMaxCount--; if(nMaxCount <= 0) throw new System.IO.IOException(); } } mBlowfish.Decrypt(mBuffer, mBuffer, mOffset, mOffset, bound); } buffer[offset++] = mBuffer[mOffset++]; count--; mCount--; totalRead++; } return totalRead; } else { int cbRead = 0; if(mCount > 0) { while((mOffset < 8) && (count > 0)) { buffer[offset++] = mBuffer[mOffset++]; count--; cbRead++; } if(mOffset == 8) { // the "wrong" signature has been transfered back // to the reader, so empty the buffer mCount = 0; mOffset = 0; } } cbRead += mStream.Read(buffer, offset, count); return cbRead; } } public override void Write(byte[] buffer, int offset, int count) { if(mIsEncrypted) { string str = System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, count); // while data are required, fill the internal buffer while(count > 0) { if(mCount == 256) { mStream.WriteByte(255); mBlowfish.Encrypt(mBuffer, mBuffer, 0, 0, 256); mStream.Write(mBuffer, 0, 256); mOffset = 0; mCount = 0; } mBuffer[mOffset++] = buffer[offset++]; count--; mCount++; } } else mStream.Write(buffer, offset, count); }
Pour simplifier les traitements, nous avons décidé que le flux doit être soit en lecture, soit en écriture, et qu'il n'est pas possible de déplacer le curseur.
The Blowfish Encryption Algorithm... Où trouver des informations sur le Blowfish
|
|
Où télécharger l'implémentation du Blowfish en c# Page d'acceuil du site de Markus Hahn, qui a implémenté le Blowfish en c#.
|
|
Télécharger le source taille : 12 Ko, dernière modification : 19/03/2003
|
|
Nous contacter Vous avez des remarques, des questions ? N'hésitez pas
à nous contacter.
|
date | révision |
---|---|
26/01/2004 | Mise à jour du lien vers le site de Markus Hahn. |