diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..398cdd2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,39 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "request": "launch", + "name": "Launch Program", + "type": "node", + "program": "${workspaceFolder}/src/mod.ts", + "cwd": "${workspaceFolder}", + "env": {}, + "runtimeExecutable": "/usr/bin/deno", + "runtimeArgs": [ + "run", + "--unstable", + "--inspect-wait", + "--allow-all" + ], + "attachSimplePort": 9229 + }, + { + "request": "launch", + "name": "Test Program", + "type": "node", + "cwd": "${workspaceFolder}", + "env": {}, + "runtimeExecutable": "/usr/bin/deno", + "runtimeArgs": [ + "test", + "--unstable", + "--inspect-wait", + "--allow-all" + ], + "attachSimplePort": 9229 + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/Private/Message.bin b/Private/Message.bin index 0c254f9..44c61df 100644 Binary files a/Private/Message.bin and b/Private/Message.bin differ diff --git a/Private/cert.pem b/Private/cert.pem new file mode 100644 index 0000000..2ee1dc0 --- /dev/null +++ b/Private/cert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICeTCCAdqgAwIBAgIUeKyiiDJdVGH3ParIry5vn/YGnaowCgYIKoZIzj0EAwIw +TjELMAkGA1UEBhMCSVQxDTALBgNVBAgMBEJhcmkxDTALBgNVBAcMBEJhcmkxITAf +BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMDIxNjM0NDVa +Fw0yNTAxMDExNjM0NDVaME4xCzAJBgNVBAYTAklUMQ0wCwYDVQQIDARCYXJpMQ0w +CwYDVQQHDARCYXJpMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQw +gZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAAAfWnGEUMElY/XIWUTPvX65HX3N5Ik +JKPdVFzDRtaTHRJKnEEvU7Z5iLAT9NpbVfCabvQXKo7LD5sjoJ1ZpSVcogDgCFCo +pmVin2ZLs5lyMtaetpVDH8m+AIlRQkkuGmkasM+OV62kzSoHl/CL4eNz1xXwqsPt +oBgvPiRFxNIE/0dz96NTMFEwHQYDVR0OBBYEFKW5mYrSXJn68diXLDjhbiEGAxJu +MB8GA1UdIwQYMBaAFKW5mYrSXJn68diXLDjhbiEGAxJuMA8GA1UdEwEB/wQFMAMB +Af8wCgYIKoZIzj0EAwIDgYwAMIGIAkIAhVgtxgnZd6KeefLjZ6Mazgr5xLDcAHyI +NsKtTw3YzT/Pztnk2ccV+NyDZyoTG72lHoPMTiB5mRSUTqORg59XQTkCQgDqHRoN +tRQlPWY3abohilRRdvYZrsoPR8FzB/M4KxT0nk10jc1wtosQ7l/XZGcKe8/k+iVs +HC5CsESzsvnp+Qslyw== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/Private/public-key.pem b/Private/public-key.pem index 51558e0..d6f7e30 100644 --- a/Private/public-key.pem +++ b/Private/public-key.pem @@ -1,6 +1,4 @@ -----BEGIN PUBLIC KEY----- -MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAAH1pxhFDBJWP1yFlEz71+uR19zeS -JCSj3VRcw0bWkx0SSpxBL1O2eYiwE/TaW1Xwmm70FyqOyw+bI6CdWaUlXKIA4AhQ -qKZlYp9mS7OZcjLWnraVQx/JvgCJUUJJLhppGrDPjletpM0qB5fwi+Hjc9cV8KrD -7aAYLz4kRcTSBP9Hc/c= +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsszGIDjEgu6k/MkW+p5Bf+UPEU/j +F9bLykzEOzP3rD/HJ2AprRpVm+PNIaLThIdUTPsO2BBBLH2CaAJ/1x65Wg== -----END PUBLIC KEY----- \ No newline at end of file diff --git a/deno.json b/deno.json index 3907642..a963245 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "tasks": { - "dev": "deno run --watch ./src/main.ts" + "dev": "deno run --watch ./src/mod.ts" }, "imports": { "@std/assert": "jsr:@std/assert@1" diff --git a/deno.lock b/deno.lock index b94ec0c..03aa00e 100644 --- a/deno.lock +++ b/deno.lock @@ -2,7 +2,8 @@ "version": "4", "specifiers": { "jsr:@std/assert@1": "1.0.9", - "jsr:@std/internal@^1.0.5": "1.0.5" + "jsr:@std/internal@^1.0.5": "1.0.5", + "npm:@types/node@*": "22.5.4" }, "jsr": { "@std/assert@1.0.9": { @@ -15,6 +16,17 @@ "integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba" } }, + "npm": { + "@types/node@22.5.4": { + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": [ + "undici-types" + ] + }, + "undici-types@6.19.8": { + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + } + }, "workspace": { "dependencies": [ "jsr:@std/assert@1" diff --git a/src/classes/Message.ts b/src/classes/Message.ts index 01ad8e8..fe4d539 100644 --- a/src/classes/Message.ts +++ b/src/classes/Message.ts @@ -11,7 +11,7 @@ export class Message { public deviceType: DeviceType; public signatureType: SignatureType; - public timestamp: bigint; + public timestamp: number; public deviceID: bigint; public location: DeviceLocation; public fields: Field[]; @@ -23,7 +23,7 @@ export class Message { deviceType: DeviceType, RESERVED: number, signatureType: SignatureType, - timestamp: bigint, + timestamp: number, deviceID: bigint, location: DeviceLocation, fields: Field[], @@ -50,7 +50,7 @@ Message ---------------------- \tDevice Type: \t${this.deviceType} \tRESERVED: \t${this.RESERVED} \tSignature Type: \t${this.signatureType} -\tTimestamp: \t${ new Date(Number(this.timestamp / 10000000n))} +\tTimestamp: \t${ new Date(this.timestamp * 1000)} \tDevice ID: \t${this.deviceID} \tLocation: \tX: ${this.location.x}\tY: ${this.location.y}\tZ: ${this.location.z} \tFields: \n`; diff --git a/src/enums/SignatureType.ts b/src/enums/SignatureType.ts index f191119..241f943 100644 --- a/src/enums/SignatureType.ts +++ b/src/enums/SignatureType.ts @@ -1,3 +1,5 @@ export enum SignatureType { - P521 = 10 + P521 = 10, + P384 = 11, + P256 = 12, } \ No newline at end of file diff --git a/src/mod.ts b/src/mod.ts index 8b13789..bd6619e 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -1 +1,2 @@ +console.log("Hu") \ No newline at end of file diff --git a/src/utils/deserializer.ts b/src/utils/deserializer.ts index 4c03d69..259eae3 100644 --- a/src/utils/deserializer.ts +++ b/src/utils/deserializer.ts @@ -4,8 +4,10 @@ import { DeviceType } from "../enums/DeviceType.ts"; import { MessageType } from "../enums/MessageType.ts"; import { SignatureType } from "../enums/SignatureType.ts"; import { DeviceLocation } from "../classes/Location.ts"; +import { signatureVerifierV1 } from "./signatureVerifier.ts"; +import * as mod from "node:crypto"; -export function deserializerV1(buffer: ArrayBuffer) { +export async function deserializerV1(buffer: ArrayBuffer, key: mod.webcrypto.CryptoKey) { const version: number = new Uint8Array(buffer.slice(0, 1))[0]; // UGLY Force typecasting @@ -31,7 +33,7 @@ export function deserializerV1(buffer: ArrayBuffer) { ] as keyof typeof SignatureType ]; - const timestamp: bigint = new BigUint64Array(buffer.slice(8, 16))[0]; + const timestamp: number = new Float64Array(buffer.slice(8, 16))[0]; // UGLY: sum the 2 bigints to a sing bigint const deviceID_Buffer = new BigUint64Array(buffer.slice(16, 32)); @@ -44,7 +46,7 @@ export function deserializerV1(buffer: ArrayBuffer) { let index = 56; let MORE_FIELDS = true; - let fields: Field[] = Array(); + const fields: Field[] = Array(); while (MORE_FIELDS) { const nextchunk = new BigUint64Array(buffer.slice(index, index + 8))[0]; @@ -71,11 +73,19 @@ export function deserializerV1(buffer: ArrayBuffer) { index += paddingBytes + 8; + const signatureStart = index + + const msgBuffer = buffer.slice(0, signatureStart) const signature = new Uint8Array(buffer.slice(index)) - if (signature.length != signatureBytesMapper(signatureType)) { - throw new Error("This signature is not valid") + const result = await signatureVerifierV1(msgBuffer, signature, key) + + if (!result) { + throw new Error("Invalid message") } + + + return new Message( version, @@ -92,12 +102,5 @@ export function deserializerV1(buffer: ArrayBuffer) { } -export function signatureBytesMapper(signatureType: SignatureType) { - switch (signatureType) { - case SignatureType.P521 : { - return 132 - } - } -} diff --git a/src/utils/signatureVerifier.ts b/src/utils/signatureVerifier.ts new file mode 100644 index 0000000..aada5c3 --- /dev/null +++ b/src/utils/signatureVerifier.ts @@ -0,0 +1,59 @@ +import * as mod from "node:crypto"; +import { atob } from "node:buffer"; + +/// Copy pasted from Mozilla +function str2ab(str: string) { + const buf = new ArrayBuffer(str.length); + const bufView = new Uint8Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} + +export async function signatureVerifierV1( + msgData: ArrayBuffer, + signature: ArrayBuffer, + Ku: mod.webcrypto.CryptoKey, +) { + // UGLY: Assuming ECDSA P-256 + + return await mod.subtle.verify( + { + name: "ECDSA", + hash: "SHA-256", + }, + Ku, + signature, + msgData, + ); +} + +export async function pem2key(filePath: string) { + const publicKeyBytes = await Deno.readFile(filePath); + const pemKey = new TextDecoder().decode(publicKeyBytes); + + // fetch the part of the PEM string between header and footer + const pemHeader = "-----BEGIN PUBLIC KEY-----"; + const pemFooter = "-----END PUBLIC KEY-----"; + const pemContents = pemKey.substring( + pemHeader.length, + pemKey.length - pemFooter.length - 1, + ); + // base64 decode the string to get the binary data + // convert from a binary string to an ArrayBuffer + const a = atob(pemContents); + const binaryDer = str2ab(a); + + // UGLY: Assuming P-256 + return mod.subtle.importKey( + "spki", + binaryDer, + { + name: "ECDSA", + namedCurve: "P-256", + }, + true, + ["verify"], + ); +} diff --git a/tests/main_test.ts b/tests/main_test.ts index 444fdcd..139a02f 100644 --- a/tests/main_test.ts +++ b/tests/main_test.ts @@ -1,12 +1,22 @@ -import { assertEquals } from "@std/assert"; +import { assertEquals, assert } from "@std/assert"; import { deserializerV1 } from "../src/utils/deserializer.ts"; +import { pem2key, signatureVerifierV1 } from "../src/utils/signatureVerifier.ts"; +import * as mod from "node:crypto"; -Deno.test(async function deserializerV1Test() { + + +Deno.test(async function verifySignatureV1Test() { const messageBuffer = (await Deno.readFile("./Private/Message.bin")).buffer - const msg = deserializerV1(messageBuffer) + const publicKey = await pem2key("./Private/public-key.pem") + const Ku = await pem2key("./Private/public-key.pem") + const msg = await deserializerV1(messageBuffer, Ku) console.log(msg.toString()) - //Assert - + +}) + +Deno.test(async function verifySignatureV1Test() { + + })