@miguel-cagide/smb2
Version:
A SMB2 implementation in TypeScript
81 lines (80 loc) • 3.51 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isMessageSigned = exports.verifyMessage = exports.signMessage = void 0;
const crypto_1 = __importDefault(require("crypto"));
const HeaderFlag_1 = __importDefault(require("./HeaderFlag"));
/**
* Byte offset of the Signature field within the SMB2 header.
* The SMB2 header is 64 bytes: signature occupies bytes 48–63.
*/
const SIGNATURE_OFFSET = 48;
const SIGNATURE_LENGTH = 16;
/**
* Byte offset of the Flags field within the SMB2 header (4 bytes, little-endian).
*/
const FLAGS_OFFSET = 16;
/**
* Signs an SMB2 message buffer **without** the 4-byte NetBIOS transport prefix.
*
* Per MS-SMB2 section 3.1.4.1 (for SMB 2.0.2 / 2.1):
* 1. Set the Signed flag (bit 3) in the Flags field.
* 2. Zero the 16-byte Signature field.
* 3. Compute HMAC-SHA-256(SigningKey, entireMessage).
* 4. Copy the first 16 bytes of the HMAC into the Signature field.
*
* @param sessionKey The 16-byte session signing key.
* @param message The SMB2 message buffer (header + body, no NetBIOS prefix).
* @returns The signed message buffer (modified in place and returned).
*/
function signMessage(sessionKey, message) {
// Set the Signed flag in the Flags field (4-byte LE at FLAGS_OFFSET)
const flags = message.readUInt32LE(FLAGS_OFFSET);
message.writeUInt32LE(flags | HeaderFlag_1.default.Signed, FLAGS_OFFSET);
// Zero the Signature field
message.fill(0, SIGNATURE_OFFSET, SIGNATURE_OFFSET + SIGNATURE_LENGTH);
// Compute HMAC-SHA-256 over the entire message
const hmac = crypto_1.default.createHmac("sha256", sessionKey);
hmac.update(message);
const signature = hmac.digest().slice(0, SIGNATURE_LENGTH);
// Write signature into the header
signature.copy(message, SIGNATURE_OFFSET);
return message;
}
exports.signMessage = signMessage;
/**
* Verifies the signature of an incoming SMB2 message buffer
* **without** the 4-byte NetBIOS transport prefix.
*
* @param sessionKey The 16-byte session signing key.
* @param message The SMB2 message buffer (header + body, no NetBIOS prefix).
* @returns `true` if the signature is valid.
*/
function verifyMessage(sessionKey, message) {
// Save the received signature
const receivedSignature = Buffer.alloc(SIGNATURE_LENGTH);
message.copy(receivedSignature, 0, SIGNATURE_OFFSET, SIGNATURE_OFFSET + SIGNATURE_LENGTH);
// Zero the Signature field for computation
message.fill(0, SIGNATURE_OFFSET, SIGNATURE_OFFSET + SIGNATURE_LENGTH);
// Compute expected HMAC-SHA-256
const hmac = crypto_1.default.createHmac("sha256", sessionKey);
hmac.update(message);
const expectedSignature = hmac.digest().slice(0, SIGNATURE_LENGTH);
// Restore the original signature
receivedSignature.copy(message, SIGNATURE_OFFSET);
// Constant-time comparison to prevent timing attacks
return crypto_1.default.timingSafeEqual(receivedSignature, expectedSignature);
}
exports.verifyMessage = verifyMessage;
/**
* Checks whether the Signed flag is set in a message's SMB2 header.
*
* @param message The SMB2 message buffer (no NetBIOS prefix).
*/
function isMessageSigned(message) {
const flags = message.readUInt32LE(FLAGS_OFFSET);
return (flags & HeaderFlag_1.default.Signed) !== 0;
}
exports.isMessageSigned = isMessageSigned;