Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,36 @@ if (args.length <= 2) {
}
var filename = process.argv[2];


p.parseFile(filename, function() {
var printresults = function() {
console.log('got', arguments);
});
}

if (args.length >=5) {
var command = process.argv[3];
var keyArg = process.argv[4];
var initializationVector = "";
var outputFile = "";

if (command == 'sign'){
outputFile = (args.length == 6) ? process.argv[5] : filename + '.signed';
}
else if(command == 'encrypt') {
if(args.length < 6){
console.log('missing correct # of args for encrypt command');
process.exit(-1);
}
initializationVector = process.argv[5];
outputFile = (args.length == 7) ? process.argv[6] : filename + '.encrypted';
}
else {
console.log('unrecognized command ', command);
process.exit(-1);
}

p.secureFile(filename, command, keyArg, initializationVector, outputFile, printresults);
}
else {
p.parseFile(filename, printresults);
}


109 changes: 109 additions & 0 deletions lib/HalModuleParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

var fs = require('fs');
var when = require('when');
var crypto = require('crypto');
var pipeline = require('when/pipeline');
var utilities = require('./utilities.js');
var ModuleInfo = require('./ModuleInfo');
Expand Down Expand Up @@ -179,6 +180,69 @@ HalModuleParser.prototype = {
});
},


/**
* Read file bytes to sign/encrypt from filename
* Read the key data (.pem or AES key bytes) to use from keyfile
* Encrypt/Sign the image file
* Write signed file to disk with outputfilename
*
* @param {String} filename, name of file to sign
* @param {String} command, encrypt or sign file
* @param {String} keyfile, name of key file to use for signing or encryption
* @param {String} keyfile, initialization vector hex string to use for encryption
* @param {String} outputfile, name of signed/encrypted image file to write to disk
* @param {Function} callback, function to call on success/failure
* @returns {Promise<Object>}
*/
secureFile: function(filename, command, keyfile, initializationvector, outputfile, callback) {
var fileInfo = {
filename: filename,
initializationvector: initializationvector
};

var that = this;
var allDone = pipeline([
function() {
return that._loadFile(filename);
},
function(fileBuffer) {
fileInfo.fileBuffer = fileBuffer;
return that.parseBuffer(fileInfo);
},
function() {
return that._loadFile(keyfile);
},
function(fileBuffer) {
fileInfo.keyBuffer = fileBuffer;
if (command == 'sign') {
that._signFile(fileInfo);
return that.parseBuffer(fileInfo);
}
else if (command == 'encrypt') {
return that._encryptFile(fileInfo);
}
},
function() {
delete fileInfo.keyBuffer;
fs.writeFileSync(outputfile, fileInfo.fileBuffer);
return fileInfo;
}
]);

if (callback) {
when(allDone).then(
function(info) {
callback(info, null);
},
function(err) {
callback(null, err);
});
}

return allDone;
},

/*
* goes and reads out the file if it exists and returns
* a promise with the fileBuffer
Expand Down Expand Up @@ -344,6 +408,7 @@ HalModuleParser.prototype = {
0x184, // Gen 2
0xC0, // Bluez
0x10C, // Core
0x20, // Tron
];

let likelyOffset = 0;
Expand Down Expand Up @@ -573,6 +638,50 @@ HalModuleParser.prototype = {
};
},

_signFile: function(fileInfo) {
// Exclude dummy signature, module suffix and crc bytes from signature
const signaturePaddingLength = 48;
const signatureLength = 64;
var bytesOffEndToExclude = signaturePaddingLength + signatureLength + fileInfo.suffixInfo.suffixSize + 4;
var bootloaderBytesToSign = fileInfo.fileBuffer.slice(fileInfo.prefixInfo.prefixOffset, -bytesOffEndToExclude);

// Calculate Signature
const signature = crypto.sign(null, bootloaderBytesToSign, fileInfo.keyBuffer);
var signatureOffset = fileInfo.fileBuffer.length - bytesOffEndToExclude + signaturePaddingLength;
for(let i = 0; i < signature.length; i++) {
fileInfo.fileBuffer.writeUInt8(signature[i], signatureOffset + i);
}

// Recalculate SHA256, exclude existing SHA, length and crc bytes from end of image
bytesOffEndToExclude = 32 + 2 + 4;
var hashBytes = fileInfo.fileBuffer.slice(0, -bytesOffEndToExclude);
var hash = Buffer.from(crypto.createHash('sha256').update(hashBytes).digest('hex'), 'hex');
var hashOffset = fileInfo.fileBuffer.length - bytesOffEndToExclude;
for(let i = 0; i < hash.length; i++) {
fileInfo.fileBuffer.writeUInt8(hash[i], hashOffset + i);
}

// Recalculate CRC32
var crcOffset = fileInfo.fileBuffer.length - 4;
var dataRegion = fileInfo.fileBuffer.slice(0, crcOffset);
var crcResult = utilities.crc32(dataRegion);
for(let i = 0; i < crcResult.length; i++) {
fileInfo.fileBuffer.writeUInt8(crcResult[i], crcOffset + i);
}

return fileInfo;
},

_encryptFile: function(fileInfo) {
const algorithm = 'aes-128-ctr'
const iv = Buffer.from(fileInfo.initializationvector, 'hex')
let cipher = crypto.createCipheriv(algorithm, fileInfo.keyBuffer, iv);
let encrypted = cipher.update(fileInfo.fileBuffer);
encrypted = Buffer.concat([encrypted, cipher.final()]);

fileInfo.fileBuffer = encrypted
return fileInfo;
},

_: null
};
Expand Down
3 changes: 2 additions & 1 deletion lib/ModuleInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ const ModuleInfoPlatform = {
BSOM: 23,
XSOM: 24,
B5SOM: 25,
ASSETTRACKER: 26
ASSETTRACKER: 26,
TRON: 32,
};

/**
Expand Down