she_decrypt
Version:
Pure JavaScript implementation for deciphering SHE arguments (M1, M2, etc)
229 lines (211 loc) • 6.86 kB
JavaScript
/** @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 -*-
*/