Repository: gchq/CyberChef (JavaScript)

Issue:
Fletcher's Checksum algorithm implementation looks wrong
**Describe the bug**
The Fletcher's Algorithm results does not match the validation values that can be found in the [Wikipedia](https://en.wikipedia.org/wiki/Fletcher%27s_checksum) article about the algorithm (I validated by implementing the algorithm myself) for Fletcher-32 and Fletcher-64. 
 
**Steps To Reproduce**
Just use the Fletcher-32 and Fletcher-64 for the input "abcdefgh".

**Expected behaviour**
The Fletcher-32 for "abcdefgh" should be `3957429649 (0xEBE19591)`.
The Fletcher-64 for "abcdefgh" should be `3543817411021686982 (0x312E2B28CCCAC8C6)`.

**Screenshots**
I don't think it's needed. Please let me know if it's needed.

**Desktop (if relevant, please complete the following information):**
 - OS: Windows 10
 - Browser: Edge (Chromium)
 - CyberChef version: 9.32.3 (current online version)

**Additional context**
Please let me know if additional context is needed.



Discussion:
Hmmm, it looks like each bytes are added instead of 16-bit or 32-bit blocks as specified in Wikipedia.

[From Hex, Fletcher-32 Checksum - CyberChef](https://gchq.github.io/CyberChef/#recipe=From_Hex%28%27Auto%27%29Fletcher-32_Checksum%28%29&input=MTIgMzQ)



Patch:
diff --git a/src/core/operations/Fletcher32Checksum.mjs b/src/core/operations/Fletcher32Checksum.mjs
index 29c74535cc..7b41ce5550 100644
--- a/src/core/operations/Fletcher32Checksum.mjs
+++ b/src/core/operations/Fletcher32Checksum.mjs
@@ -35,10 +35,18 @@ class Fletcher32Checksum extends Operation {
     run(input, args) {
         let a = 0,
             b = 0;
-        input = new Uint8Array(input);
+        if (ArrayBuffer.isView(input)) {
+            input = new DataView(input.buffer, input.byteOffset, input.byteLength);
+        } else {
+            input = new DataView(input);
+        }
 
-        for (let i = 0; i < input.length; i++) {
-            a = (a + input[i]) % 0xffff;
+        for (let i = 0; i < input.byteLength - 1; i += 2) {
+            a = (a + input.getUint16(i, true)) % 0xffff;
+            b = (b + a) % 0xffff;
+        }
+        if (input.byteLength % 2 !== 0) {
+            a = (a + input.getUint8(input.byteLength - 1)) % 0xffff;
             b = (b + a) % 0xffff;
         }
 
diff --git a/src/core/operations/Fletcher64Checksum.mjs b/src/core/operations/Fletcher64Checksum.mjs
index 1d0d5bd97c..68328ea324 100644
--- a/src/core/operations/Fletcher64Checksum.mjs
+++ b/src/core/operations/Fletcher64Checksum.mjs
@@ -35,10 +35,22 @@ class Fletcher64Checksum extends Operation {
     run(input, args) {
         let a = 0,
             b = 0;
-        input = new Uint8Array(input);
+        if (ArrayBuffer.isView(input)) {
+            input = new DataView(input.buffer, input.byteOffset, input.byteLength);
+        } else {
+            input = new DataView(input);
+        }
 
-        for (let i = 0; i < input.length; i++) {
-            a = (a + input[i]) % 0xffffffff;
+        for (let i = 0; i < input.byteLength - 3; i += 4) {
+            a = (a + input.getUint32(i, true)) % 0xffffffff;
+            b = (b + a) % 0xffffffff;
+        }
+        if (input.byteLength % 4 !== 0) {
+            let lastValue = 0;
+            for (let i = 0; i < input.byteLength % 4; i++) {
+                lastValue = (lastValue << 8) | input.getUint8(input.byteLength - 1 - i);
+            }
+            a = (a + lastValue) % 0xffffffff;
             b = (b + a) % 0xffffffff;
         }
 


Test patch:
diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs
index 19e709709c..fe1c4e00d5 100644
--- a/tests/operations/index.mjs
+++ b/tests/operations/index.mjs
@@ -124,6 +124,7 @@ import "./tests/UnescapeString.mjs";
 import "./tests/LS47.mjs";
 import "./tests/LZString.mjs";
 import "./tests/NTLM.mjs";
+import "./tests/FletcherChecksum.mjs";
 
 // Cannot test operations that use the File type yet
 // import "./tests/SplitColourChannels.mjs";
diff --git a/tests/operations/tests/FletcherChecksum.mjs b/tests/operations/tests/FletcherChecksum.mjs
new file mode 100644
index 0000000000..de23abdcfd
--- /dev/null
+++ b/tests/operations/tests/FletcherChecksum.mjs
@@ -0,0 +1,108 @@
+/**
+ * @author mikecat
+ * @copyright Crown Copyright 2022
+ * @license Apache-2.0
+ */
+import TestRegister from "../../lib/TestRegister.mjs";
+
+TestRegister.addTests([
+    {
+        name: "Fletcher-16 Checksum: abcde",
+        input: "abcde",
+        expectedOutput: "c8f0",
+        recipeConfig: [
+            {
+                op: "Fletcher-16 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-16 Checksum: abcdef",
+        input: "abcdef",
+        expectedOutput: "2057",
+        recipeConfig: [
+            {
+                op: "Fletcher-16 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-16 Checksum: abcdefgh",
+        input: "abcdefgh",
+        expectedOutput: "0627",
+        recipeConfig: [
+            {
+                op: "Fletcher-16 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-32 Checksum: abcde",
+        input: "abcde",
+        expectedOutput: "f04fc729",
+        recipeConfig: [
+            {
+                op: "Fletcher-32 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-32 Checksum: abcdef",
+        input: "abcdef",
+        expectedOutput: "56502d2a",
+        recipeConfig: [
+            {
+                op: "Fletcher-32 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-32 Checksum: abcdefgh",
+        input: "abcdefgh",
+        expectedOutput: "ebe19591",
+        recipeConfig: [
+            {
+                op: "Fletcher-32 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-64 Checksum: abcde",
+        input: "abcde",
+        expectedOutput: "c8c6c527646362c6",
+        recipeConfig: [
+            {
+                op: "Fletcher-64 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-64 Checksum: abcdef",
+        input: "abcdef",
+        expectedOutput: "c8c72b276463c8c6",
+        recipeConfig: [
+            {
+                op: "Fletcher-64 Checksum",
+                args: [],
+            },
+        ],
+    },
+    {
+        name: "Fletcher-64 Checksum: abcdefgh",
+        input: "abcdefgh",
+        expectedOutput: "312e2b28cccac8c6",
+        recipeConfig: [
+            {
+                op: "Fletcher-64 Checksum",
+                args: [],
+            },
+        ],
+    },
+]);
diff --git a/tests/operations/tests/GenerateAllHashes.mjs b/tests/operations/tests/GenerateAllHashes.mjs
index 28707bded3..8e4a849a51 100644
--- a/tests/operations/tests/GenerateAllHashes.mjs
+++ b/tests/operations/tests/GenerateAllHashes.mjs
@@ -58,8 +58,8 @@ CTPH:         A:E:E
 Checksums:
 Fletcher-8:   3d
 Fletcher-16:  5dc1
-Fletcher-32:  045901c0
-Fletcher-64:  00000459000001c0
+Fletcher-32:  3f5cd9e7
+Fletcher-64:  7473657474736574
 Adler-32:     045d01c1
 CRC-8:        b9
 CRC-16:       f82e