O CRC – Cyclic redundancy check, ou verificação de redundância cíclica, é um código detector de erros cujo algoritmo é muito usado em protocolos de comunicação diferentes, empacotamento e desempacotamento de algoritmos para garantir a robustez dos dados.
A ideia por trás do CRC é simples – calcular um checksum original (sequência de verificação de quadros) para cada quadro de dados, baseada em seu conteúdo, e colar o checksum no final de cada mensagem. Uma vez que os dados são recebidos, é possível realizar o mesmo cálculo e comparar os resultados – se os resultados são semelhantes, a mensagem é válida.
O CRC é calculado e anexado na informação a transmitir (ou armazenar), sendo verificado após a recepção ou o acesso, para confirmar se não ocorreram alterações.
O CRC é popular por ser simples de implementar em hardware binário, simples de ser analisado matematicamente, e pela eficiência em detectar erros típicos causados por ruído em canais de transmissão.
A utilidade do CRC advém das seguintes propriedades:
- Como todos os bits são usados no cálculo do CRC, a mudança em apenas um bit provoca uma mudança no CRC.
- Mesmo mudanças pequenas nos dados levam a CRCs muito diferentes. Experiências com o CRC-32 (usando polinômios de 32 bits) mostram que é muito raro que a introdução de erros nos dados não seja detectada pelo CRC.
- A probabilidade de qualquer dos 232 valores possíveis para o CRC é praticamente uniforme.
Existem diferentes tipos de CRC que podem ser calculados: CRC-32, CRC-16, CRC-12, CRC-8 etc.
Para realizarmos cálculos envolvendo o CRC temos que utilizar o namespace System.Security.Cryptography e neste artigo eu vou calcular o CRC de strings e arquivos.
Vamos abrir o Visual C# 2010 Express Edition e, no menu File-> New Poject, selecione o Template Windows Forms Applicacion com o nome Calculando_CRC.
No menu Project -> Add Class, inclua uma classe com o nome CrcStream com o seguinte código:
using System.IO;
namespace Macoratti
{
/// <summary>
/// Encapsula um <see cref="System.IO.Stream" /> para calcular o checksum CRC32
/// em tempo de execução
/// </summary>
public class CrcStream : Stream
{
/// <summary>
/// Encapsula um <see cref="System.IO.Stream" />.
/// </summary>
/// <param name="stream">O stream para calcular o checksum.</param>
public CrcStream(Stream stream)
{
this.stream = stream;
}
Stream stream;
/// <summary>
/// Obtem o stream.
/// </summary>
public Stream Stream
{
get { return stream; }
}
public override bool CanRead
{
get { return stream.CanRead; }
}
public override bool CanSeek
{
get { return stream.CanSeek; }
}
public override bool CanWrite
{
get { return stream.CanWrite; }
}
public override void Flush()
{
stream.Flush();
}
public override long Length
{
get { return stream.Length; }
}
public override long Position
{
get
{
return stream.Position;
}
set
{
stream.Position = value;
}
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count)
{
count = stream.Read(buffer, offset, count);
readCrc = CalculateCrc(readCrc, buffer, offset, count);
return count;
}
public override void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
writeCrc = CalculateCrc(writeCrc, buffer, offset, count);
}
uint CalculateCrc(uint crc, byte[] buffer, int offset, int count)
{
unchecked
{
for (int i = offset, end = offset + count; i < end; i++)
crc = (crc >> 8) ^ table[(crc ^ buffer[i]) & 0xFF];
}
return crc;
}
static private uint[] table = GenerateTable();
static private uint[] GenerateTable()
{
unchecked
{
uint[] table = new uint[256];
uint crc;
const uint poly = 0xEDB88320;
for (uint i = 0; i < table.Length; i++)
{
crc = i;
for (int j = 8; j > 0; j--)
{
if ((crc & 1) == 1)
crc = (crc >> 1) ^ poly;
else
crc >>= 1;
}
table[i] = crc;
}
return table;
}
}
uint readCrc = unchecked(0xFFFFFFFF);
/// <summary>
/// Obtem o checksum CRC dos dados que foram lidos pelo stream
/// </summary>
public uint ReadCrc
{
get { return unchecked(readCrc ^ 0xFFFFFFFF); }
}
uint writeCrc = unchecked(0xFFFFFFFF);
/// <summary>
/// Obtem o checksum CRC dos dados que foram escritos para o stream
/// </summary>
public uint WriteCrc
{
get { return unchecked(writeCrc ^ 0xFFFFFFFF); }
}
/// <summary>
/// Reseta a leitura e escrita dos checksums.
/// </summary>
public void ResetChecksum()
{
readCrc = unchecked(0xFFFFFFFF);
writeCrc = unchecked(0xFFFFFFFF);
}
}
}
autor: http://www.codeproject.com/Members/reinux
Agora vamos definir no formulário form1.cs uma interface bem simples, na qual iremos informar o nome do arquivo e calcular o seu CRC.
Abaixo, vemos o formulário que usa os controles TextBox e Button:

No evento Click do botão de comando – Calcula CRC -, vamos incluir o código que usa a classe CrcStream para calcular o CRC do arquivo:
using System;
using System.Windows.Forms;
using System.IO;
using Macoratti;
namespace Calculando_CRC
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
FileStream file = null;
CrcStream stream = null;
private void btnCalculaCRC_Click(object sender, EventArgs e)
{
if (txtArquivo.Text == string.Empty)
{
MessageBox.Show("Informe o nome do arquivo.");
return;
}
string arquivo = txtArquivo.Text;
//Abre um fluxo de stream e o encapsula em um CrcStream
try
{
file = new FileStream(arquivo, FileMode.Open);
stream = new CrcStream(file);
}
catch (Exception ex)
{
MessageBox.Show("Erro ao acessar o arquivo : " + ex.Message);
return;
}
//Usa o arquivo - neste caso le o arquivo como uma string
StreamReader reader = new StreamReader(stream);
string texto = reader.ReadToEnd();
//Imprime o checksum calculado
txtCRC.Text = stream.ReadCrc.ToString("X8");
}
}
}
Executando o projeto, iremos obter para um determinado arquivo informado:

Pegue o projeto completo aqui: Calculando_CRC.zip




