Skip to content

Instantly share code, notes, and snippets.

@mStirner
Created March 22, 2020 00:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mStirner/b670e4603e477aa19a912fe04af51a58 to your computer and use it in GitHub Desktop.
Save mStirner/b670e4603e477aa19a912fe04af51a58 to your computer and use it in GitHub Desktop.
*tgz verification (for signed plugins)
  • Quick & dirty tar.gz/.tgz verification
  • add extra header filed
  • sub header contains:
    • Author information (email & name)
    • Signature from server (public + private key)

lib coming soon...

const fs = require("fs");
const crypto = require('crypto');
//const bitwise = require("bitwise");
const privateKey = fs.readFileSync("./private.pem");
// http://www.zlib.org/rfc-gzip.html
// http://www.onicos.com/staff/iz/formats/gzip.html
// https://de.wikipedia.org/wiki/Gzip
// https://dev.to/somedood/bitmasks-a-very-esoteric-and-impractical-way-of-managing-booleans-1hlf
// https://www.npmjs.com/package/bitwise
// https://stackoverflow.com/questions/1436438/how-do-you-set-clear-and-toggle-a-single-bit-in-javascript
function createSubHeader(key, payload) {
// get charcode from key
let s1 = key.charCodeAt(0);
let s2 = key.charCodeAt(1);
// calculate length bytes
let l2 = Math.floor(payload.length / 256);
let l1 = payload.length - (l2 * 256);
/*
let arr = [];
for (let i = 0; i < payload.length; i++) {
arr.push(payload.charCodeAt(i));
}
*/
console.log("Len compar: %d - %d", payload.length, l2 * 256 + l1)
return Buffer.concat([
Buffer.from([s1, s2, l1, l2]),
Buffer.from(payload)
]);
}
fs.readFile("./test-plugin.tgz", (err, bytes) => {
if (err) {
console.log(err);
process.exit(100);
}
/*
console.log("File length, bytes: %d", bytes.length);
console.log();
// bitwise operation on header flags
const FLAG_RESERVED_3 = (bytes[3] >> 7) & 1;
const FLAG_RESERVED_2 = (bytes[3] >> 6) & 1;
const FLAG_RESERVED_1 = (bytes[3] >> 5) & 1;
const FLAG_COMMENT = (bytes[3] >> 4) & 1;
const FLAG_NAME = (bytes[3] >> 3) & 1;
const FLAG_EXTRA = (bytes[3] >> 2) & 1;
const FLAG_CRC = (bytes[3] >> 1) & 1;
const FLAG_TEXT = (bytes[3] >> 0) & 1;
console.log("FLAG_RESERVED_3", FLAG_RESERVED_3);
console.log("FLAG_RESERVED_2", FLAG_RESERVED_2);
console.log("FLAG_RESERVED_1", FLAG_RESERVED_1);
console.log("FLAG_COMMENT", FLAG_COMMENT);
console.log("FLAG_NAME", FLAG_NAME);
console.log("FLAG_EXTRA", FLAG_EXTRA);
console.log("FLAG_CRC", FLAG_CRC);
console.log("FLAG_TEXT", FLAG_TEXT);
console.log();
let HEADER_EXTRA_LENGTH = 0;
let HEADER_EXTRA_OBJECT = {};
let HEADER_NAME_LENGTH = 0;
let HEADER_NAME = "";
let HEADER_COMMENT_LENGTH = 0;
let HEADER_COMMENT = "";
round
let BODY_START_BYTE = 10; // = header length
let BODY_END_BYTE = bytes.length - 8;
if (FLAG_EXTRA) {
let offset = 0;
let len1 = bytes[10];
let len2 = bytes[11];
HEADER_EXTRA_LENGTH = len1 + (len2 * 256);
BODY_START_BYTE += HEADER_EXTRA_LENGTH + 2;
console.log("Extra header length", HEADER_EXTRA_LENGTH);
let extra = bytes.slice(12, 12 + HEADER_EXTRA_LENGTH);
while (HEADER_EXTRA_LENGTH > offset) {
let s1 = extra[offset + 0];
let s2 = extra[offset + 1];
let l1 = extra[offset + 2];
let l2 = extra[offset + 3];
let length = l1 + (l2 * 256);
let end = offset + 4 + length;
// read & store sub-header in object
HEADER_EXTRA_OBJECT[`${String.fromCharCode(s1)}${String.fromCharCode(s2)}`] = extra.slice(offset + 4, end).toString();
// set offset
offset = end;
}
console.log(HEADER_EXTRA_OBJECT);
}
if (FLAG_NAME) {
let start = 10;
let offset = 0;
let counter = 0;
// add extra header length to offset
// + 2 for length bytes for extra header
offset += HEADER_EXTRA_LENGTH;
if (FLAG_EXTRA) {
// + 2 for length bytes
offset += 2;
}
// read til we reach the "zero" terminating
while (bytes[start + offset + counter] !== 0) {
HEADER_NAME += String.fromCharCode(bytes[start + offset + counter]);
counter += 1;
}
HEADER_NAME_LENGTH = counter;
BODY_START_BYTE += counter + 1; // +1 for zero terminating
console.log("Original name: '%s'", HEADER_NAME);
}
if (FLAG_COMMENT) {
let start = 10;
let offset = 0;
let counter = 0;
// add offset
offset += HEADER_EXTRA_LENGTH;
offset += HEADER_NAME_LENGTH;
if (FLAG_EXTRA) {
// for length bytes
offset += 2;
}
if (FLAG_NAME) {
// + 1 for zero terminating
// original name field
offset += 1;
}
// read til we reach the "zero" terminating
while (bytes[start + offset + counter] !== 0) {
HEADER_COMMENT += String.fromCharCode(bytes[start + offset + counter]);
counter += 1;
}
HEADER_COMMENT_LENGTH = counter;
BODY_START_BYTE += counter + 1; // +1 for zero terminating
console.log("Comment: '%s'", HEADER_COMMENT);
}
if (FLAG_CRC) {
HEADER_CRC_LENGTH = 2;
BODY_START_BYTE += 2;
}
*/
let body = bytes.slice(10, bytes.length - 8);
console.log("Body length:", body.length);
console.log(Buffer.from(body).toString("base64"));
console.log();
var signer = crypto.createSign('sha256');
signer.update(body); // -> this is the tar body
var sign = signer.sign(privateKey, 'base64');
console.log("SIGN:", sign);
console.log();
let payload = Buffer.concat([
createSubHeader("vs", sign),
//createSubHeader("vd", "abcdefghijklmnopäääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääää"), // ERROR
// createSubHeader("vd", "="), // OK
createSubHeader("ai", "eyJuYW1lIjoiTWFyYyBTdGlybmVyIiwiZW1haWwiOiJtYXJjLnN0aXJuZXJAb3Blbi1oYXVzLmlvIn0=")
]);
// calculate length bytes
let toround = payload.length / 256;
let l2 = Math.floor(toround);
let l1 = payload.length - (l2 * 256);
console.log("to round", toround);
console.log("len1: %d len2: %d, payload: %d", l1, l2, payload.length)
let EXTRA_HEADER = Buffer.concat([
Buffer.from([l1, l2]),
payload
]);
//console.log(EXTRA_HEADER.length - 2)
// set extra header bits
//bytes[3] &= ~(1 << 0); // FTEXT
//bytes[3] &= ~(1 << 1); // FHCRC
bytes[3] |= (1 << 2); // FEXTRA
//bytes[3] &= ~(1 << 3); // FNAME
//bytes[3] &= ~(1 << 4); // FCOMMENT
//bytes[3] &= ~(1 << 5); // reserved
//bytes[3] &= ~(1 << 6); // reserved
//bytes[3] &= ~(1 << 7); // reserved
// split file
let head = bytes.slice(0, 10);
let tail = bytes.slice(10, bytes.length); // 10 -> 11 plugin wird verifiziert, lässt sich aber nicht mehr öffnen!
let content = Buffer.concat([
head,
EXTRA_HEADER,
tail
]);
fs.writeFileSync("./plugin-signed.tgz", content);
//console.log(EXTRA_HEADER[0], EXTRA_HEADER[1])
});
const fs = require("fs");
const crypto = require('crypto');
//const bitwise = require("bitwise");
const publicKey = fs.readFileSync("./public.pem");
// http://www.zlib.org/rfc-gzip.html
// http://www.onicos.com/staff/iz/formats/gzip.html
// https://de.wikipedia.org/wiki/Gzip
// https://dev.to/somedood/bitmasks-a-very-esoteric-and-impractical-way-of-managing-booleans-1hlf
// https://www.npmjs.com/package/bitwise
// https://stackoverflow.com/questions/1436438/how-do-you-set-clear-and-toggle-a-single-bit-in-javascript
fs.readFile("./plugin-signed.tgz", (err, bytes) => {
if (err) {
console.log(err);
process.exit(100);
}
console.log("File length, bytes: %d", bytes.length);
console.log();
//let header = bytes.slice(0, 10);
//let flags = header[3];
//let eFlags = header[8];
//let OS = header[9];
/*
console.log("Is tarfile:", header[0] === 31 && header[1] === 139);
console.log("compress method:", header[2] === 8 ? "deflate" : "other");
console.log("M-Date: %d%d%d%d", bytes[4], bytes[5], bytes[6], bytes[7]);
console.log("OS", OS);
console.log("flags", flags);
console.log();
*/
// bitwise operation on header flags
const FLAG_RESERVED_3 = (bytes[3] >> 7) & 1;
const FLAG_RESERVED_2 = (bytes[3] >> 6) & 1;
const FLAG_RESERVED_1 = (bytes[3] >> 5) & 1;
const FLAG_COMMENT = (bytes[3] >> 4) & 1;
const FLAG_NAME = (bytes[3] >> 3) & 1;
const FLAG_EXTRA = (bytes[3] >> 2) & 1;
const FLAG_CRC = (bytes[3] >> 1) & 1;
const FLAG_TEXT = (bytes[3] >> 0) & 1;
console.log("FLAG_RESERVED_3", FLAG_RESERVED_3);
console.log("FLAG_RESERVED_2", FLAG_RESERVED_2);
console.log("FLAG_RESERVED_1", FLAG_RESERVED_1);
console.log("FLAG_COMMENT", FLAG_COMMENT);
console.log("FLAG_NAME", FLAG_NAME);
console.log("FLAG_EXTRA", FLAG_EXTRA);
console.log("FLAG_CRC", FLAG_CRC);
console.log("FLAG_TEXT", FLAG_TEXT);
console.log();
let HEADER_EXTRA_LENGTH = 0;
let HEADER_EXTRA_OBJECT = {};
let HEADER_NAME_LENGTH = 0;
let HEADER_NAME = "";
let HEADER_COMMENT_LENGTH = 0;
let HEADER_COMMENT = "";
let HEADER_CRC_LENGTH = 0;
let HEADER_CRC = "";
let BODY_START_BYTE = 10; // = header length
let BODY_END_BYTE = bytes.length - 8;
if (FLAG_EXTRA) {
let offset = 0;
let len1 = bytes[10];
let len2 = bytes[11];
console.log("len1: %d, len2: %d", len1, len2)
HEADER_EXTRA_LENGTH = len1 + (len2 * 256);
BODY_START_BYTE += HEADER_EXTRA_LENGTH + 2;
console.log("Extra header length", HEADER_EXTRA_LENGTH);
let extra = bytes.slice(12, 12 + HEADER_EXTRA_LENGTH);
while (HEADER_EXTRA_LENGTH > offset) {
let s1 = extra[offset + 0];
let s2 = extra[offset + 1];
let l1 = extra[offset + 2];
let l2 = extra[offset + 3];
let length = l1 + (l2 * 256);
let end = offset + 4 + length;
// read & store sub-header in object
HEADER_EXTRA_OBJECT[`${String.fromCharCode(s1)}${String.fromCharCode(s2)}`] = extra.slice(offset + 4, end).toString();
// set offset
offset = end;
}
console.log(HEADER_EXTRA_OBJECT);
}
if (FLAG_NAME) {
let start = 10;
let offset = 0;
let counter = 0;
// add extra header length to offset
// + 2 for length bytes for extra header
offset += HEADER_EXTRA_LENGTH;
if (FLAG_EXTRA) {
// + 2 for length bytes
offset += 2;
}
// read til we reach the "zero" terminating
while (bytes[start + offset + counter] !== 0) {
HEADER_NAME += String.fromCharCode(bytes[start + offset + counter]);
counter += 1;
}
HEADER_NAME_LENGTH = counter;
BODY_START_BYTE += counter + 1; // +1 for zero terminating
console.log("Original name: '%s'", HEADER_NAME);
}
if (FLAG_COMMENT) {
let start = 10;
let offset = 0;
let counter = 0;
// add offset
offset += HEADER_EXTRA_LENGTH;
offset += HEADER_NAME_LENGTH;
if (FLAG_EXTRA) {
// for length bytes
offset += 2;
}
if (FLAG_NAME) {
// + 1 for zero terminating
// original name field
offset += 1;
}
// read til we reach the "zero" terminating
while (bytes[start + offset + counter] !== 0) {
HEADER_COMMENT += String.fromCharCode(bytes[start + offset + counter]);
counter += 1;
}
HEADER_COMMENT_LENGTH = counter;
BODY_START_BYTE += counter + 1; // +1 for zero terminating
console.log("Comment: '%s'", HEADER_COMMENT);
}
if (FLAG_CRC) {
HEADER_CRC_LENGTH = 2;
BODY_START_BYTE += 2;
}
let body = bytes.slice(BODY_START_BYTE, BODY_END_BYTE);
console.log("Body length:", body.length);
console.log(Buffer.from(body).toString("base64"));
console.log();
var verifier = crypto.createVerify('sha256');
verifier.update(body); // -> this is the tar body
var ver = verifier.verify(publicKey, HEADER_EXTRA_OBJECT["vs"], "base64");
console.log("Signature: %s", HEADER_EXTRA_OBJECT["vs"]);
console.log();
console.log("Plugin is verified: ", ver);
let json = Buffer.from(HEADER_EXTRA_OBJECT["ai"], 'base64').toString("ascii");
console.log(JSON.parse(json))
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment