mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-13 12:34:16 +00:00
112 lines
3.9 KiB
JavaScript
112 lines
3.9 KiB
JavaScript
//
|
|
// Created by Mingliang Chen on 17/8/1.
|
|
// illuspas[a]gmail.com
|
|
// Copyright (c) 2018 Nodemedia. All rights reserved.
|
|
//
|
|
const Crypto = require("crypto")
|
|
|
|
const MESSAGE_FORMAT_0 = 0
|
|
const MESSAGE_FORMAT_1 = 1
|
|
const MESSAGE_FORMAT_2 = 2
|
|
|
|
const RTMP_SIG_SIZE = 1536
|
|
const SHA256DL = 32
|
|
|
|
const RandomCrud = Buffer.from([
|
|
0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8,
|
|
0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
|
|
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
|
|
0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
|
|
])
|
|
|
|
const GenuineFMSConst = "Genuine Adobe Flash Media Server 001"
|
|
const GenuineFMSConstCrud = Buffer.concat([Buffer.from(GenuineFMSConst, "utf8"), RandomCrud])
|
|
|
|
const GenuineFPConst = "Genuine Adobe Flash Player 001"
|
|
const GenuineFPConstCrud = Buffer.concat([Buffer.from(GenuineFPConst, "utf8"), RandomCrud])
|
|
|
|
function calcHmac(data, key) {
|
|
let hmac = Crypto.createHmac("sha256", key)
|
|
hmac.update(data)
|
|
return hmac.digest()
|
|
}
|
|
|
|
function GetClientGenuineConstDigestOffset(buf) {
|
|
let offset = buf[0] + buf[1] + buf[2] + buf[3]
|
|
offset = (offset % 728) + 12
|
|
return offset
|
|
}
|
|
|
|
function GetServerGenuineConstDigestOffset(buf) {
|
|
let offset = buf[0] + buf[1] + buf[2] + buf[3]
|
|
offset = (offset % 728) + 776
|
|
return offset
|
|
}
|
|
|
|
function detectClientMessageFormat(clientsig) {
|
|
let computedSignature, msg, providedSignature, sdl
|
|
sdl = GetServerGenuineConstDigestOffset(clientsig.slice(772, 776))
|
|
msg = Buffer.concat([clientsig.slice(0, sdl), clientsig.slice(sdl + SHA256DL)], 1504)
|
|
computedSignature = calcHmac(msg, GenuineFPConst)
|
|
providedSignature = clientsig.slice(sdl, sdl + SHA256DL)
|
|
if (computedSignature.equals(providedSignature)) {
|
|
return MESSAGE_FORMAT_2
|
|
}
|
|
sdl = GetClientGenuineConstDigestOffset(clientsig.slice(8, 12))
|
|
msg = Buffer.concat([clientsig.slice(0, sdl), clientsig.slice(sdl + SHA256DL)], 1504)
|
|
computedSignature = calcHmac(msg, GenuineFPConst)
|
|
providedSignature = clientsig.slice(sdl, sdl + SHA256DL)
|
|
if (computedSignature.equals(providedSignature)) {
|
|
return MESSAGE_FORMAT_1
|
|
}
|
|
return MESSAGE_FORMAT_0
|
|
}
|
|
|
|
function generateS1(messageFormat) {
|
|
let randomBytes = Crypto.randomBytes(RTMP_SIG_SIZE - 8)
|
|
let handshakeBytes = Buffer.concat([Buffer.from([0, 0, 0, 0, 1, 2, 3, 4]), randomBytes], RTMP_SIG_SIZE)
|
|
|
|
let serverDigestOffset
|
|
if (messageFormat === 1) {
|
|
serverDigestOffset = GetClientGenuineConstDigestOffset(handshakeBytes.slice(8, 12))
|
|
} else {
|
|
serverDigestOffset = GetServerGenuineConstDigestOffset(handshakeBytes.slice(772, 776))
|
|
}
|
|
|
|
let msg = Buffer.concat([handshakeBytes.slice(0, serverDigestOffset), handshakeBytes.slice(serverDigestOffset + SHA256DL)], RTMP_SIG_SIZE - SHA256DL)
|
|
let hash = calcHmac(msg, GenuineFMSConst)
|
|
hash.copy(handshakeBytes, serverDigestOffset, 0, 32)
|
|
return handshakeBytes
|
|
}
|
|
|
|
function generateS2(messageFormat, clientsig, callback) {
|
|
let randomBytes = Crypto.randomBytes(RTMP_SIG_SIZE - 32)
|
|
let challengeKeyOffset
|
|
if (messageFormat === 1) {
|
|
challengeKeyOffset = GetClientGenuineConstDigestOffset(clientsig.slice(8, 12))
|
|
} else {
|
|
challengeKeyOffset = GetServerGenuineConstDigestOffset(clientsig.slice(772, 776))
|
|
}
|
|
let challengeKey = clientsig.slice(challengeKeyOffset, challengeKeyOffset + 32)
|
|
let hash = calcHmac(challengeKey, GenuineFMSConstCrud)
|
|
let signature = calcHmac(randomBytes, hash)
|
|
let s2Bytes = Buffer.concat([randomBytes, signature], RTMP_SIG_SIZE)
|
|
return s2Bytes
|
|
}
|
|
|
|
function generateS0S1S2(clientsig) {
|
|
let clientType = Buffer.alloc(1, 3)
|
|
let messageFormat = detectClientMessageFormat(clientsig)
|
|
let allBytes
|
|
if (messageFormat === MESSAGE_FORMAT_0) {
|
|
// Logger.debug("[rtmp handshake] using simple handshake.")
|
|
allBytes = Buffer.concat([clientType, clientsig, clientsig])
|
|
} else {
|
|
// Logger.debug("[rtmp handshake] using complex handshake.")
|
|
allBytes = Buffer.concat([clientType, generateS1(messageFormat), generateS2(messageFormat, clientsig)])
|
|
}
|
|
return allBytes
|
|
}
|
|
|
|
module.exports = { generateS0S1S2 }
|