UNPKG

she_decrypt

Version:

Pure JavaScript implementation for deciphering SHE arguments (M1, M2, etc)

229 lines (211 loc) 6.86 kB
#!/usr/bin/env node /** @fileOverview * Javascript cryptography implementation * for MiyaguchiPreneel Compression function. * * Copyright �2023-2024 RENAULT GROUP - AMPERE "R�mi COHEN SCALI <remi.cohen-scali@ampere.cars>" */ (function(root) { "use strict"; /*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */ /*global document, window, escape, unescape, module, require, Uint32Array */ var aesjs = require('aes-js'); const aesCmac = require('node-aes-cmac').aesCmac; var MP = require('miyaguchipreneel'); /* * dk = KDF(k) * * Key Derivation Function used in the SHE protocol specification * */ SHE_decrypt.prototype.KDF = (k) => { return( SHE_decrypt.prototype.mp.comp( SHE_decrypt.prototype.bufferIV, Buffer.concat( [ (k instanceof Buffer ? Buffer.from(k) : Buffer.from(k, 'hex') ), SHE_decrypt.prototype.KeyUpdateEncCte ] ) ) ); } /* * bufM2 = decrypt_M2(msg, key) * * This method will decipher the SHE command M2 argument register * provided for a Key Provisionning. * This register will also allows, when deciphered, to get CID, FID * and Key. * (see SHE protocol specification on AUTOSAR web site for details) * * Arguments: * msg: The message ciphered transfered in a CAN/Eth frame * key: The kMasterEcu key used for ciphering the frame * * Returns: * The deciphered M2 register value for SHE (Secure Hardware Extension) */ SHE_decrypt.prototype.decrypt_M2 = (msg, key) => { var aesCbc = new aesjs.ModeOfOperation.cbc( aesjs.utils.hex.toBytes(SHE_decrypt.prototype.KDF(key).toString('hex')), aesjs.utils.hex.toBytes(SHE_decrypt.prototype.bufferIV.toString('hex')) ); var m2Str = aesCbc.decrypt( aesjs.utils.hex.toBytes((msg instanceof Buffer ? msg.toString('hex') : msg)) ); return(Buffer.from(m2Str)); } /* * SHE_decrypt constructor * */ function SHE_decrypt() { const KeyUpdateEncCte = Buffer.from('010153484500800000000000000000b0', 'hex'); const bufferIV = Buffer.from('00000000000000000000000000000000', 'hex'); const mp = new MP(); this.KeyUpdateEncCte = KeyUpdateEncCte; this.bufferIV = bufferIV; this.mp = mp; SHE_decrypt.prototype.KeyUpdateEncCte = KeyUpdateEncCte; SHE_decrypt.prototype.bufferIV = bufferIV; SHE_decrypt.prototype.mp = mp; SHE_decrypt.prototype.KDF = this.KDF; SHE_decrypt.prototype.decrypt_M2 = this.decrypt_M2; /* * M3valid = check_M3(msg, key) * * This method will compute the SHE M3 integrity figure for checking * * Arguments: * msg: The message ciphered transfered in a CAN/Eth frame * key: The kMasterEcu key used for ciphering the frame * * Returns: * The deciphered M2 register value for SHE (Secure Hardware Extension) */ SHE_decrypt.prototype.check_M3 = (Knew, M1, M2, M3) => { var m3new = aesCmac( Buffer.from(SHE_decrypt.prototype.KDF(Knew).toString('hex'), 'hex'), Buffer.concat([M1, M2]), { returnAsBuffer: true } ).toString('hex'); var m3old = M3.toString('hex'); console.info("M3 old = '%s'", m3old); console.info("M3 new = '%s'", m3new); var valid = (m3new == m3old); console.info("Valid = %s", valid ? "YES" : "NO"); return valid; } /* * cid = getCID(frame) * * Extract CID from the SHE command deciphered argument register M2 * * Arguments: * frame: The deciphered M2 argument register of the SHE command * * Returns: * CID extracted from the SHE command registers */ SHE_decrypt.prototype.getCID = (frame) => { return(frame.subarray(16,48).subarray(0, 4).toString('hex').substring(0, 7)); } /* * fid = getFID(frame) * * Extract FID from the SHE command deciphered argument register M2 * * Arguments: * frame: The deciphered M2 argument register of the SHE command * * Returns: * FID extracted from the SHE command registers */ SHE_decrypt.prototype.getFID = (frame) => { var decM2 = frame.subarray(16,48); return(((decM2[3] & 0x0F) << 1) + ((decM2[4] >> 7) & 0x01)); } /* * key = getKEY(frame) * * Extract KEY provisionned from the SHE command deciphered argument register M2 * * Arguments: * frame: The deciphered M2 argument register of the SHE command * * Returns: * KEY extracted from the SHE command registers */ SHE_decrypt.prototype.getKEY = (frame) => { var decM2 = frame.subarray(16,48); return(decM2.subarray(16,48)); } /* * channel = getChannel(frame) * * Extract the channel from the SHE command argument registers * * Arguments: * frame: The M1|M2|M3 argument registers of the SHE command * * Returns: * Channel extracted from the SHE command registers */ SHE_decrypt.prototype.getChannel = (msg) => { if (msg instanceof Buffer) { return(Number(msg.toString('hex')[30])-3); } else { return(Number(msg[30])-3); } } return(this); } // NodeJS if (typeof exports !== 'undefined') { exports.SHE_decrypt = SHE_decrypt; exports.KDF = SHE_decrypt.prototype.KDF; exports.decrypt_M2 = SHE_decrypt.prototype.decrypt_M2; exports.check_M3 = SHE_decrypt.prototype.check_M3; exports.getCID = SHE_decrypt.prototype.getCID; exports.getFID = SHE_decrypt.prototype.getFID; exports.getKey = SHE_decrypt.prototype.getKey; exports.getChannel = SHE_decrypt.prototype.getChannel; module.exports = SHE_decrypt; } // RequireJS/AMD // http://www.requirejs.org/docs/api.html // https://github.com/amdjs/amdjs-api/wiki/AMD else if (typeof(define) === 'function' && define.amd) { define([], function() { return SHE_decrypt; }); } // Web Browsers else { root.SHE_decrypt = SHE_decrypt; } })(this); /* * vim: et:ts=4:sw=4:sts=4 * -*- mode: JavaScript; coding: utf-8-unix; tab-width: 4 -*- */