Articles technique
Encryptage avec le Compact Framework
sur PocketPC via un Stream "BlowFish"
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...
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 11 Ko, dernière modification 06/08/2013 | |
Nous contacter Vous avez des remarques, des questions ? N'hésitez pas à nous contacter. |
Historique de révisions...
date | révision |
---|---|
19/12/2005 00:00 | Mise à jour du lien vers le site de Markus Hahn. |
26/01/2004 00:00 | Mise à jour du lien vers le site de Markus Hahn. |