"{ Encoding: utf8 }"
"{ Package: 'stx:libbasic2' }"
"{ NameSpace: Smalltalk }"
HashStream subclass:#CRCStream
instanceVariableNames:'crc generatorPolynom crcTable initValue xorOut'
classVariableNames:''
poolDictionaries:''
category:'System-Crypt-Hashing'
!
CRCStream class instanceVariableNames:'crcTables'
"
No other class instance variables are inherited by this class.
"
!
!CRCStream class methodsFor:'documentation'!
documentation
"
abstract superclass of crc streams;
refactored from original crc32 stream.
For details, see https://en.wikipedia.org/wiki/Cyclic_redundancy_check
Only use CRC to protect against communication errors;
DO NOT use CRC for cryptography, authentication, security, etc.
- use secure hashes for those instead.
[parameters:]
polynomials:
CRC_POLY_16 0xA001
CRC_POLY_32 0xEDB88320L
CRC_POLY_CCITT 0x1021
CRC_POLY_DNP 0xA6BC
CRC_POLY_KERMIT 0x8408
start values:
CRC_START_8 0x00
CRC_START_16 0x0000
CRC_START_MODBUS 0xFFFF
CRC_START_XMODEM 0x0000
CRC_START_CCITT_1D0F 0x1D0F
CRC_START_CCITT_FFFF 0xFFFF
CRC_START_KERMIT 0x0000
CRC_START_SICK 0x0000
CRC_START_DNP 0x0000
CRC_START_32 0xFFFFFFFF
"
! !
!CRCStream class methodsFor:'initialization'!
crcTableFor:generatorPolynomInteger
"construct the polynom-specific lookup table"
|crcTable|
"/ CRC8Stream flushCrcTables
"/ CRC8Stream crcTableFor:(16r1D bitReversed8)
crcTables isNil ifTrue:[
crcTables := Dictionary new
].
crcTable := (crcTables at:generatorPolynomInteger ifAbsent:nil).
crcTable isNil ifTrue:[
"/ for crc16 and crc8, we waste some memory
"/ (could use WordArray or ByteArray);
"/ but that would need three writeBytes implementations.
"/ Not worth the saving.
crcTable := IntegerArray new:256.
"/ least-sign. bit towards most significant bit...
0 to:255 do:[:count| |i|
i := count.
8 timesRepeat:[
(i bitTest:1) ifTrue:[
i := generatorPolynomInteger bitXor:(i bitShift:-1)
] ifFalse:[
i := i bitShift:-1
]
].
crcTable at:count+1 put:i.
].
crcTables at:generatorPolynomInteger put:crcTable.
].
^ crcTable.
"Created: / 16-03-2019 / 20:53:51 / Claus Gittinger"
"Modified: / 24-03-2019 / 12:38:12 / Claus Gittinger"
!
flushCrcTables
crcTables := nil.
"
CRC16Stream flushCrcTables
CRC32Stream flushCrcTables
"
"Created: / 16-03-2019 / 23:41:19 / Claus Gittinger"
! !
!CRCStream class methodsFor:'instance creation'!
generatorPolynom:anLSBInteger
"notice, in literature, the generator polynom is usually specified as an MSB number"
^ self basicNew
generatorPolynom:anLSBInteger
"
self assert:((self generatorPolynom:16r82F63B78)
nextPut:'123456789';
hashValue) = 16rE3069283
"
"Modified (format): / 17-03-2019 / 14:03:42 / Claus Gittinger"
!
generatorPolynom:anLSBInteger initValue:initValue
"notice, in literature, the generator polynom is usually specified as an MSB number"
^ self basicNew
generatorPolynom:anLSBInteger
initValue:initValue
"
self assert:((self generatorPolynom:16r82F63B78)
nextPut:'123456789';
hashValue) = 16rE3069283
"
"Created: / 16-03-2019 / 21:15:54 / Claus Gittinger"
"Modified (format): / 17-03-2019 / 14:03:37 / Claus Gittinger"
!
generatorPolynom:anLSBInteger initValue:initValue xorOut:xorOut
"notice, in literature, the generator polynom is usually specified as an MSB number"
^ self basicNew
generatorPolynom:anLSBInteger
initValue:initValue xorOut:xorOut
"
self assert:((self generatorPolynom:16r82F63B78)
nextPut:'123456789';
hashValue) = 16rE3069283
"
"Created: / 16-03-2019 / 21:16:05 / Claus Gittinger"
"Modified (format): / 17-03-2019 / 14:03:30 / Claus Gittinger"
! !
!CRCStream methodsFor:'accessing'!
generatorPolynom
"answer the generator polynom (LSB)"
^ generatorPolynom
"Modified (comment): / 16-03-2019 / 20:58:10 / Claus Gittinger"
!
initValue
"answer the init value"
^ initValue ? 0
"Created: / 16-03-2019 / 21:05:04 / Claus Gittinger"
!
xorOut
"answer the xorOut value"
^ xorOut ? 16rFFFFFFFF
"Created: / 16-03-2019 / 21:16:23 / Claus Gittinger"
! !
!CRCStream methodsFor:'initialization'!
generatorPolynom:polyLSB initValue:initValueArg xorOut:xorOutArg
"set the generator polynom for this instance.
And set start and xorOut.
Computes the crcTable for this polynom.
Notice the bit order is LSB"
generatorPolynom := polyLSB.
crc := initValue := initValueArg.
xorOut := xorOutArg.
crcTable := self class crcTableFor:generatorPolynom.
"Created: / 16-03-2019 / 21:17:12 / Claus Gittinger"
"Modified (comment): / 17-03-2019 / 12:25:11 / Claus Gittinger"
!
reset
"reset the current crc value"
crc := initValue.
"Created: / 16-03-2019 / 21:25:27 / Claus Gittinger"
! !
!CRCStream methodsFor:'queries'!
hashValue
"return the computed CRC"
^ crc bitXor:xorOut.
"Modified: / 16-03-2019 / 21:27:59 / Claus Gittinger"
! !
!CRCStream methodsFor:'writing'!
nextPutBytes:count from:anObject startingAt:start
"add the hash of anObject to the computed hash so far."
%{
int len, offs;
// fetch first - check later
len = __intVal(count);
offs = __intVal(start) - 1;
if (__bothSmallInteger(count, start)) {
int objSize;
unsigned char *extPtr;
// the most common first
if (__isStringLike(anObject)) {
objSize = __stringSize(anObject);
extPtr = (unsigned char *)__stringVal(anObject);
} else if (__isByteArray(anObject)) {
objSize = __byteArraySize(anObject);
extPtr = (unsigned char *)__byteArrayVal(anObject);
} else if (__isExternalBytesLike(anObject)) {
OBJ sz = __externalBytesSize(anObject);
extPtr = (unsigned char *)__externalBytesAddress(anObject);
if (__isSmallInteger(sz)) {
objSize = __intVal(sz);
} else {
objSize = 0; /* unknown */
}
} else {
int nInstVars, nInstBytes;
OBJ oClass = __Class(anObject);
switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
case BYTEARRAY:
case WORDARRAY:
case LONGARRAY:
case SWORDARRAY:
case SLONGARRAY:
case FLOATARRAY:
case DOUBLEARRAY:
break;
default:
goto bad;
}
nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
nInstBytes = __OBJS2BYTES__(nInstVars);
// nInstBytes is the number of bytes occupied by pointer instance variables
// subtract from size and add to byte-pointer
objSize = __qSize(anObject) - OHDR_SIZE - nInstBytes;
extPtr = (unsigned char *)__byteArrayVal(anObject)+nInstBytes;
}
if ((offs >= 0) && (len >= 0) && (objSize >= (len + offs))) {
unsigned int _crc;
unsigned int *_crcTable = __integerArrayVal( __INST(crcTable) );
unsigned char *cp = extPtr+offs;
unsigned int n = len;
_crc = (unsigned int) (__intVal( __INST(crc) ));
#if __POINTER_SIZE__ != 8
if (!__isSmallInteger(__INST(crc))) {
_crc = __unsignedLongIntVal( __INST(crc) );
}
#endif
#ifdef __LSBFIRST__
# if __POINTER_SIZE__ == 8
if (((unsigned INT)cp & 7) == 0) {
// longword aligned
for ( ; n >= 8 ; n -= 8, cp += 8) {
unsigned INT lWord;
unsigned char _idx;
lWord = ((unsigned INT *)cp)[0];
_idx = (_crc ^ lWord) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (lWord>>8)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (lWord>>16)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (lWord>>24)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (lWord>>32)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (lWord>>40)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (lWord>>48)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (lWord>>56)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
}
}
# endif // __POINTER_SIZE__ == 8
if (((unsigned INT)cp & 3) == 0) {
// word aligned
for ( ; n >= 4 ; n -= 4, cp += 4) {
unsigned int word;
unsigned char _idx;
word = ((unsigned int *)cp)[0];
_idx = (_crc ^ word) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (word>>8)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (word>>16)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ (word>>24)) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
}
}
#endif // LSBFIRST
for ( ; n >= 4 ; n -= 4, cp += 4) {
unsigned char _idx;
_idx = (_crc ^ cp[0]) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ cp[1]) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ cp[2]) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
_idx = (_crc ^ cp[3]) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
}
while (n-- > 0) {
unsigned char _idx = (_crc ^ *cp++) & 0xFF;
_crc = _crcTable[_idx] ^ (_crc >> 8);
}
#if __POINTER_SIZE__ == 8
__INST(crc) = __MKSMALLINT(_crc);
#else
if (_crc <= _MAX_INT) {
__INST(crc) = __MKSMALLINT(_crc);
} else {
// this code fails with gcc 4.7.2:
// __INST(crc) = __MKUINT(_crc); __STORESELF(crc);
OBJ temp = __MKUINT(_crc);
__INST(crc) = temp; __STORESELF(crc);
}
#endif
RETURN (count);
}
}
bad: ;
%}.
ArgumentError raise
"Created: / 09-01-2012 / 16:48:35 / cg"
"Modified: / 06-06-2019 / 23:16:48 / Claus Gittinger"
! !
!CRCStream class methodsFor:'documentation'!
version_CVS
^ '$Header$'
! !