Skip to content

Commit 978cbd0

Browse files
authored
fix(rt): CRC32C incorrect result on inputs longer than 7 bytes (#766)
1 parent e842c93 commit 978cbd0

File tree

3 files changed

+39
-14
lines changed

3 files changed

+39
-14
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"id": "4c3348fe-3e51-411b-98e6-6ac2e6a2bba0",
3+
"type": "bugfix",
4+
"description": "Fix incorrect CRC32c output when trying to hash more than 7 bytes",
5+
"module": "runtime"
6+
}

runtime/hashing/common/src/aws/smithy/kotlin/runtime/hashing/Crc32c.kt

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package aws.smithy.kotlin.runtime.hashing
66

77
import aws.smithy.kotlin.runtime.util.InternalApi
88
import kotlin.experimental.and
9-
import kotlin.experimental.xor
109

1110
/**
1211
* Compute the CRC32C hash of the current [ByteArray]
@@ -64,48 +63,48 @@ public class Crc32c : Crc32Base() {
6463
*/
6564
private class CRC32CImpl {
6665
/** the current CRC value, bit-flipped */
67-
var crc = 0xffffffff
66+
var crc = 0xffffffff.toInt()
6867

69-
fun reset() { crc = 0xffffffff }
68+
fun reset() { crc = 0xffffffff.toInt() }
7069

7170
fun update(b: ByteArray, offset: Int, length: Int) {
7271
var localCrc = crc
7372
var off = offset
7473
var len = length
7574

7675
while (len > 7) {
77-
val c0 = (b[off + 0] xor localCrc.toByte()) and 0xff.toByte()
78-
val c1 = (b[off + 1] xor ((localCrc ushr 8).toByte())) and 0xff.toByte()
76+
val c0 = (b[off + 0].toInt() xor localCrc) and 0xff
7977
localCrc = localCrc ushr 8
80-
val c2 = (b[off + 2] xor ((localCrc ushr 8).toByte())) and 0xff.toByte()
78+
val c1 = (b[off + 1].toInt() xor localCrc) and 0xff
8179
localCrc = localCrc ushr 8
82-
val c3 = (b[off + 3] xor ((localCrc ushr 8).toByte())) and 0xff.toByte()
83-
localCrc = (T[T8_7_start + c0] xor T[T8_6_start + c1]) xor (T[T8_5_start + c2] xor T[T8_4_start + c3])
80+
val c2 = (b[off + 2].toInt() xor localCrc) and 0xff
81+
localCrc = localCrc ushr 8
82+
val c3 = (b[off + 3].toInt() xor localCrc) and 0xff
83+
localCrc = (T[T8_7_start + c0] xor T[T8_6_start + c1] xor T[T8_5_start + c2] xor T[T8_4_start + c3]).toInt()
8484

8585
val c4 = b[off + 4] and 0xff.toByte()
8686
val c5 = b[off + 5] and 0xff.toByte()
8787
val c6 = b[off + 6] and 0xff.toByte()
8888
val c7 = b[off + 7] and 0xff.toByte()
8989

90-
localCrc = localCrc xor (T[T8_3_start + c4] xor T[T8_2_start + c5]) xor (T[T8_1_start + c6] xor T[T8_0_start + c7])
90+
localCrc = localCrc xor (T[T8_3_start + c4] xor T[T8_2_start + c5] xor T[T8_1_start + c6] xor T[T8_0_start + c7]).toInt()
9191

9292
off += 8
9393
len -= 8
9494
}
9595

96-
for (i in 1..len) {
97-
localCrc = ((localCrc ushr 8) xor T[((T8_0_start + ((localCrc xor b[off].toLong()) and 0xff)).toInt())])
96+
for (i in 0 until len) {
97+
localCrc = (localCrc ushr 8 xor T[T8_0_start + (localCrc xor b[off].toInt() and 0xff)].toInt())
9898
off += 1
9999
}
100100

101-
// Publish localCrc out to object
102101
crc = localCrc
103102
}
104103

105-
fun getValue(): Long = crc.inv() and 0xffffffffL
104+
fun getValue(): Int = crc.inv()
106105

107106
fun update(b: Int) {
108-
crc = (crc ushr 8) xor (T[(T8_0_start + ((crc xor b.toLong()) and 0xff)).toInt()])
107+
crc = crc ushr 8 xor T[(T8_0_start + ((crc xor b) and 0xff))].toInt()
109108
}
110109

111110
companion object {

runtime/hashing/common/test/aws/smithy/kotlin/runtime/hashing/Crc32cTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,24 @@ class Crc32cTest {
6060
crc.digest()
6161
assertEquals(0U, crc.digestValue()) // checksum should be reset
6262
}
63+
64+
@Test
65+
fun testNonAsciiInput() {
66+
val crc = Crc32c()
67+
val input = byteArrayOf(0)
68+
crc.update(input, 0, 1)
69+
val bytes = crc.digest()
70+
71+
assertEquals("Un1TUQ==", bytes.encodeBase64String())
72+
}
73+
74+
@Test
75+
fun testLargeInput() {
76+
val crc = Crc32c()
77+
val input = ByteArray(1024) { 0 }
78+
crc.update(input, 0, input.size)
79+
80+
val bytes = crc.digest()
81+
assertEquals("7q7efA==", bytes.encodeBase64String())
82+
}
6383
}

0 commit comments

Comments
 (0)