Flow Group SASFlow Group
L'erp des Processus Relationnels
Systeme d'Information – Audit Industriel
> Accueil > Expertises & Savoirs > Articles techniques
<div class="infotip"><b>Espace client&#160;:</b> <a href="login.aspx">suivez ce lien</a> pour entrer dans l'espace qui vous est réservé.</div>

Articles technique


Encryptage avec le Compact Framework
sur PocketPC via un Stream "BlowFish"

read the English version English version

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 sensibles.

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.

Implémentation

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és 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); }

Limitations

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.

Quelques liens utiles...

Historique de révisions...

daterévision
19/12/2005 00:00Mise à jour du lien vers le site de Markus Hahn.
26/01/2004 00:00Mise à jour du lien vers le site de Markus Hahn.

les informations fournies ici le sont en tant que telles, sans aucune garantie d'aucune sorte.
© 2022 Flow Group SAS - Flow Group est une marque déposée de GL Conseil SA.