最近搞一個協議,以實現隱蔽通道,其中需要使用CRC校正演算法,由於資料位元數比較少,最後決定使用位的CRC校正演算法。
該演算法主要就是實現一個模二運算,基本原理就是異或,移位。
模二運算的演算法如下(C語言描述):
模二運算
// CrcMOD2函數///////////////////////////////////////////////////////
// 作用:模2運算
// 參數說明;
// m —— 被除數
// p —— 除數
// 返回:餘數
unsigned long CrcMOD2(unsigned long m, unsigned long p)
{
int m_bits = 0, p_bits = 0, a = 1, bit = 0, flag = 0;
unsigned long m_temp = m, p_temp = p;
unsigned long remainder = 0, andData = 0x00000001;
unsigned long dividend, divisor;
// 得到被除數位元
while (m_temp)
{
m_temp /= 2;
++m_bits;
}
// 得到除數位元
while (p_temp)
{
p_temp /= 2;
++p_bits;
}
// 如果被除數位元小於除數,則直接返回被除數作為餘數
if (m_bits < p_bits)
return m;
// 在此開始第一次模2運算
m_temp = m >> (m_bits - p_bits); // 被除數右移相應的位元
dividend = m_temp; // 得到第一次進行運算的被除數
divisor = p; // 得到除數
remainder = dividend ^ divisor; // 得到模2運算的結果作為餘數
m_bits -= p_bits; // 第一次計算完成,減去已經計算過的位元
while (m_bits)
{
if (!flag)
{
dividend = (remainder << 1); // 上一次得到的餘數作為這次被除數的高位
m_temp = m >> (m_bits - 1);
bit = andData & m_temp;
dividend |= bit; // 原被除數的某一位作為現在的被除數的最低位
}
else
{
dividend <<= 1;
m_temp = m >> (m_bits - 1);
bit = andData & m_temp;
dividend |= bit;
}
// 比較除數和被除數的最高位大小
if ((dividend & (andData << (p_bits - 1))) >= (divisor & (andData << (p_bits - 1))))
{
flag = 0;
remainder = dividend ^ divisor; // 得到模2運算的結果作為餘數
}
else
{
// 需要借位
flag = 1;
}
--m_bits;
}
if (flag)
remainder = dividend;
return remainder;
}
CrcGetCode函數獲未經處理資料和CRC產生多項式,利用模二運算得到新的資料。演算法如下:給資料加上校正碼
// CrcGetCode函數///////////////////////////////////////////////////
// 作用:通過未經處理資料與CRC多項式,得到整個資料的編碼
// 參數說明:
// originalData —— 未經處理資料
// crcPolynomial —— CRC產生多項式
// 返回:未經處理資料 + 校正碼
int CrcGetCode(unsigned long originalData, unsigned long crcPolynomial)
{
unsigned long checkBits = 0, temp = crcPolynomial, m = originalData, fcs;
while (temp)
{
temp /= 2;
++checkBits; // 校正位個數加一
}
-- checkBits; // 得到校正位個數(比產生多項式少1位)
m <<= checkBits; // 得到模二運算的被除數
if (checkBits == 0)
return m;
fcs = CrcMOD2(m, crcPolynomial);
m |= fcs; // 加上FCS校正子
return m; // 返回整個編碼
}