Search code examples
rubycrc16

Generating CRC16 checksums in ruby for files


First off, let me explain that I have next to no idea what any of this means, so if I say anything dumb, please let me know.

I'm working on a system which is going to convert xml strings and files into hexpair strings to embed into smart cards and send across the web. This bit is working just fine.

Part of this process, however, involves also generating a checksum for the string/file, for which I've been given some sample C# code (sorry for the screenshot, it's taken from a PDF file):

enter image description here

My job is to convert this code into Ruby, but I'm only having partial success.

I've been given some sample strings and images with which to test this, all of which can be found in this spec

require 'spec_helper'
require 'checksum_calculator'

describe ChecksumCalculator do
  describe '.call' do
    subject { described_class.call(data) }

    context 'when passed xml' do
      let(:data) { '<Card><RegNo>00000003</><Title>Mr</><Initial>B</><Surname>Black</><PrintDate>01-Feb-2004</><ExpiryDate>Dec 2012</><Colour>Black</><Scheme>CSCS</><Type>Senior Manager</><IssuedBy>Construction Skills</><Foil>H+S Test</><Top>CONSTRUCTION SKILLS CERTIFICATION SCHEME</><Bottom>The registered holder of this card holds the~construction qualifications listed on the reverse</><Back><Line>NVQ Construction Site Management L5</></Back><LogoID>3</></Card>' }

      it 'returns "8B5A"' do
        expect(subject).to eq '8B5A'
      end
    end

    context 'when passed Lorem ipsum' do
      let(:data) { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ut consectetur justo, in semper enim. Curabitur placerat varius diam. Suspendisse dapibus dui sapien, ac mattis mi aliquam sit amet. Phasellus interdum magna et urna rutrum elementum. Fusce odio risus, laoreet vel velit sit amet, convallis egestas metus. Nunc tincidunt, ligula ut lobortis facilisis, nulla sem semper dui, eget consectetur ligula mi eu felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas ipsum metus, feugiat eget pretium in, ultricies sit amet leo. Mauris sed facilisis turpis, quis porta sapien. In hac habitasse platea dictumst. Integer gravida, tortor nec pharetra ornare, nulla ipsum sagittis risus, nec cursus justo lacus vel sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque quis sem at ante posuere sodales non sit amet dolor. Mauris sagittis magna sed aliquam lacinia. Phasellus nec sapien maximus, fringilla urna a, commodo mauris.' }

      it 'returns "9034"' do
        expect(subject).to eq '9034'
      end
    end

    context 'when passed "Hello World"' do
      let(:data) { 'Hello World' }

      it 'returns "B2DA"' do
        expect(subject).to eq 'B2DA'
      end
    end

    context 'when passed "CSCS Data"' do
      let(:data) { 'CSCS Data' }

      it 'returns "9583"' do
        expect(subject).to eq '9583'
      end
    end

    context 'when passed "0123456789"' do
      let(:data) { '0123456789' }

      it 'returns "829E"' do
        expect(subject).to eq '829E'
      end
    end

    context 'when passed 2k_michael_knight.jpg' do
      let(:data) { File.read(File.join(Rails.root, 'spec', 'fixtures', '2k_michael_knight.jpg')) }

      it 'returns "5404"' do
        expect(subject).to eq '5404'
      end
    end

    context 'when passed 2k_lego_dude.jpg' do
      let(:data) { File.read(File.join(Rails.root, 'spec', 'fixtures', '2k_lego_dude.jpg')) }

      it 'returns "53005"' do
        expect(subject).to eq '53005'
      end
    end
  end
end

And here is the code which I've written (it uses the digest-crc gem):

require 'digest/crc16_ccitt'

class ChecksumCalculator
  def self.call(data)
    crc = Digest::CRC16CCITT.new
    crc << data
    (crc.checksum ^ 0xffff).to_s(16).upcase
  end
end

but while the specs for the strings are passing just fine, the images are not.

Failures:

    1) ChecksumCalculator.call when passed 2k_lego_dude.jpg returns "53005" Failure/Error: expect(subject).to eq '53005'

expected: "53005"
got: "CF0D"

(compared using ==)
# ./spec/lib/checksum_calculator_spec.rb:58:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'

    2) ChecksumCalculator.call when passed 2k_michael_knight.jpg returns "5404" Failure/Error: expect(subject).to eq '5404'

expected: "5404"
got: "151C"

(compared using ==)
# ./spec/lib/checksum_calculator_spec.rb:51:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'

I have a feeling that the code is working fine, but there's something wrong with the way that I'm passing in the image. Can anyone help?

For reference, here are the images:

Thank you


Solution

  • Your code is correct. The test cases are wrong.

    For some reason most of the test cases compare with a hex value, but the two jpeg files compare with a decimal value. CF0D in hex is 53005 in decimal. 151C in hex is 5404 in decimal.

    The immediate clue was that 53005 has five digits, but a 16-bit hex value can only have four.

    By the way, that CRC is the Genibus CRC-16. It is neither the true nor false CCITT CRC-16. See this catalog.