Produits  
  Services et Conseils  
  Fiches Technique  
  SipXTapi avec .Net  
  transformNode en .Net  
  Blowfish et le CF  
  MD5 et le CF  
  Compression HTTP et le CF  
 
 

  Fiches Technique  


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

read the 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 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.

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

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.

Historique de révisions...

date révision
26/01/2004 Mise à 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.
Copyright © FlowGroup SAS, 2002-2005