2019-06-30 21:28:00 -04:00
/ * *
* @ author mshwed [ m @ ttshwed . com ]
* @ copyright Crown Copyright 2019
* @ license Apache - 2.0
* /
2019-07-09 12:23:59 +01:00
import Operation from "../Operation.mjs" ;
import OperationError from "../errors/OperationError.mjs" ;
2019-07-02 15:13:11 -04:00
2019-07-09 12:23:59 +01:00
import { toHexFast } from "../lib/Hex.mjs" ;
2019-06-30 21:28:00 -04:00
/ * *
* CRC - 8 Checksum operation
* /
class CRC8Checksum extends Operation {
/ * *
* CRC8Checksum constructor
* /
constructor ( ) {
super ( ) ;
this . name = "CRC-8 Checksum" ;
this . module = "Crypto" ;
2019-07-02 15:13:11 -04:00
this . description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961." ;
this . infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check" ;
2019-06-30 21:28:00 -04:00
this . inputType = "ArrayBuffer" ;
this . outputType = "string" ;
this . args = [
{
2019-07-02 15:30:59 -04:00
"name" : "Algorithm" ,
"type" : "option" ,
"value" : [
"CRC-8" ,
"CRC-8/CDMA2000" ,
"CRC-8/DARC" ,
"CRC-8/DVB-S2" ,
"CRC-8/EBU" ,
"CRC-8/I-CODE" ,
"CRC-8/ITU" ,
"CRC-8/MAXIM" ,
"CRC-8/ROHC" ,
"CRC-8/WCDMA"
]
2019-06-30 21:28:00 -04:00
}
2019-07-02 15:30:59 -04:00
] ;
2019-07-01 19:02:07 -04:00
}
2019-07-02 15:13:11 -04:00
/ * *
2019-07-02 15:30:59 -04:00
* Generates the pre - computed lookup table for byte division
*
* @ param polynomial
2019-07-02 15:13:11 -04:00
* /
calculateCRC8LookupTable ( polynomial ) {
const crc8Table = new Uint8Array ( 256 ) ;
let currentByte ;
for ( let i = 0 ; i < 256 ; i ++ ) {
currentByte = i ;
for ( let bit = 0 ; bit < 8 ; bit ++ ) {
2019-07-02 15:30:59 -04:00
if ( ( currentByte & 0x80 ) !== 0 ) {
2019-07-02 15:13:11 -04:00
currentByte <<= 1 ;
currentByte ^= polynomial ;
} else {
currentByte <<= 1 ;
}
}
2019-07-01 19:02:07 -04:00
2019-07-02 15:13:11 -04:00
crc8Table [ i ] = currentByte ;
2019-07-02 15:30:59 -04:00
}
2019-07-02 15:13:11 -04:00
return crc8Table ;
2019-07-01 19:02:07 -04:00
}
/ * *
2019-07-02 15:13:11 -04:00
* Calculates the CRC - 8 Checksum from an input
2019-07-02 15:30:59 -04:00
*
2019-07-02 15:13:11 -04:00
* @ param { ArrayBuffer } input
* @ param { number } polynomial
* @ param { number } initializationValue
* @ param { boolean } inputReflection
* @ param { boolean } outputReflection
* @ param { number } xorOut
2019-07-01 19:02:07 -04:00
* /
2019-07-02 15:30:59 -04:00
calculateCRC8 ( input , polynomial , initializationValue , inputReflection , outputReflection , xorOut ) {
const crcSize = 8 ;
2019-07-02 15:13:11 -04:00
const crcTable = this . calculateCRC8LookupTable ( polynomial ) ;
2019-07-02 15:30:59 -04:00
let crc = initializationValue !== 0 ? initializationValue : 0 ;
2019-07-02 15:13:11 -04:00
let currentByte , position ;
input = new Uint8Array ( input ) ;
2019-07-02 15:30:59 -04:00
for ( const inputByte of input ) {
2019-07-02 15:13:11 -04:00
currentByte = inputReflection ? this . reverseBits ( inputByte , crcSize ) : inputByte ;
2019-07-02 15:30:59 -04:00
position = ( currentByte ^ crc ) & 255 ;
2019-07-02 15:13:11 -04:00
crc = crcTable [ position ] ;
2019-07-01 19:02:07 -04:00
}
2019-07-02 15:30:59 -04:00
crc = outputReflection ? this . reverseBits ( crc , crcSize ) : crc ;
2019-07-02 15:13:11 -04:00
2019-07-02 15:30:59 -04:00
if ( xorOut !== 0 ) crc = crc ^ xorOut ;
2019-07-02 15:13:11 -04:00
2019-07-03 15:07:26 +01:00
return toHexFast ( new Uint8Array ( [ crc ] ) ) ;
2019-06-30 21:28:00 -04:00
}
/ * *
2019-07-02 15:30:59 -04:00
* Reverse the bits for a given input byte .
*
* @ param { number } input
2019-07-02 15:13:11 -04:00
* /
reverseBits ( input , hashSize ) {
let reversedByte = 0 ;
for ( let i = hashSize - 1 ; i >= 0 ; i -- ) {
reversedByte |= ( ( input & 1 ) << i ) ;
input >>= 1 ;
}
return reversedByte ;
}
/ * *
* @ param { ArrayBuffer } input
2019-06-30 21:28:00 -04:00
* @ param { Object [ ] } args
* @ returns { string }
* /
run ( input , args ) {
2019-07-01 19:02:07 -04:00
const algorithm = args [ 0 ] ;
2019-06-30 21:28:00 -04:00
2019-07-03 15:07:26 +01:00
switch ( algorithm ) {
case "CRC-8" :
return this . calculateCRC8 ( input , 0x7 , 0x0 , false , false , 0x0 ) ;
case "CRC-8/CDMA2000" :
return this . calculateCRC8 ( input , 0x9B , 0xFF , false , false , 0x0 ) ;
case "CRC-8/DARC" :
return this . calculateCRC8 ( input , 0x39 , 0x0 , true , true , 0x0 ) ;
case "CRC-8/DVB-S2" :
return this . calculateCRC8 ( input , 0xD5 , 0x0 , false , false , 0x0 ) ;
case "CRC-8/EBU" :
return this . calculateCRC8 ( input , 0x1D , 0xFF , true , true , 0x0 ) ;
case "CRC-8/I-CODE" :
return this . calculateCRC8 ( input , 0x1D , 0xFD , false , false , 0x0 ) ;
case "CRC-8/ITU" :
return this . calculateCRC8 ( input , 0x7 , 0x0 , false , false , 0x55 ) ;
case "CRC-8/MAXIM" :
return this . calculateCRC8 ( input , 0x31 , 0x0 , true , true , 0x0 ) ;
case "CRC-8/ROHC" :
return this . calculateCRC8 ( input , 0x7 , 0xFF , true , true , 0x0 ) ;
case "CRC-8/WCDMA" :
return this . calculateCRC8 ( input , 0x9B , 0x0 , true , true , 0x0 ) ;
default :
throw new OperationError ( "Unknown checksum algorithm" ) ;
2019-07-01 19:02:07 -04:00
}
2019-06-30 21:28:00 -04:00
}
}
export default CRC8Checksum ;