diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 9078e250..abb25146 100755
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -321,6 +321,7 @@
"Entropy",
"Frequency distribution",
"Chi Square",
+ "Haversine distance",
"Detect File Type",
"Scan for Embedded Files",
"Disassemble x86",
diff --git a/src/core/operations/HaversineDistance.mjs b/src/core/operations/HaversineDistance.mjs
new file mode 100644
index 00000000..3e7bc506
--- /dev/null
+++ b/src/core/operations/HaversineDistance.mjs
@@ -0,0 +1,58 @@
+/**
+ * @author Dachande663 [dachande663@gmail.com]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import OperationError from "../errors/OperationError";
+
+/**
+ * HaversineDistance operation
+ */
+class HaversineDistance extends Operation {
+
+ /**
+ * HaversineDistance constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Haversine distance";
+ this.module = "Default";
+ this.description = "Returns the distance between two pairs of GPS latitude and longitude co-ordinates in metres.
e.g. 51.487263,-0.124323, 38.9517,-77.1467
";
+ this.inputType = "string";
+ this.outputType = "number";
+ this.args = [];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {number}
+ */
+ run(input, args) {
+
+ const values = input.match(/^(-?\d+(\.\d+)?), ?(-?\d+(\.\d+)?), ?(-?\d+(\.\d+)?), ?(-?\d+(\.\d+)?)$/);
+ if (!values) {
+ throw new OperationError("Input must in the format lat1, lng1, lat2, lng2");
+ }
+
+ const lat1 = parseFloat(values[1]);
+ const lng1 = parseFloat(values[3]);
+ const lat2 = parseFloat(values[6]);
+ const lng2 = parseFloat(values[8]);
+
+ const TO_RAD = Math.PI / 180;
+ const dLat = (lat2-lat1) * TO_RAD;
+ const dLng = (lng2-lng1) * TO_RAD;
+ const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * TO_RAD) * Math.cos(lat2 * TO_RAD) * Math.sin(dLng/2) * Math.sin(dLng/2);
+ const metres = 6371000 * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+
+ return metres;
+
+ }
+
+}
+
+export default HaversineDistance;
diff --git a/test/index.mjs b/test/index.mjs
index f9cbac7e..e06a1470 100644
--- a/test/index.mjs
+++ b/test/index.mjs
@@ -44,6 +44,7 @@ import "./tests/operations/ConditionalJump";
import "./tests/operations/Register";
import "./tests/operations/Comment";
import "./tests/operations/Hash";
+import "./tests/operations/HaversineDistance";
import "./tests/operations/Hexdump";
import "./tests/operations/Image";
import "./tests/operations/MorseCode";
diff --git a/test/tests/operations/HaversineDistance.mjs b/test/tests/operations/HaversineDistance.mjs
new file mode 100644
index 00000000..dc10492b
--- /dev/null
+++ b/test/tests/operations/HaversineDistance.mjs
@@ -0,0 +1,22 @@
+/**
+ * Haversine distance tests.
+ *
+ * @author Dachande663 [dachande663@gmail.com]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister";
+
+TestRegister.addTests([
+ {
+ name: "Haversine distance",
+ input: "51.487263,-0.124323, 38.9517,-77.1467",
+ expectedOutput: "5619355.701829259",
+ recipeConfig: [
+ {
+ "op": "Haversine distance",
+ "args": []
+ }
+ ],
+ }
+]);