Arquivo da tag: crc

C# – Calculando o CRC de strings e arquivos

Fonte: José Carlos Macoratti/IMasters

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:

  1. 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.
  2. 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.
  3. 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