jt-framework
jt-framework copied to clipboard
求教 消息体 加密如何处理
求教 消息体 加密如何处理
消息头,消息属性中的 第10位,11位,12位 为 010 时,表示消息体经过SM4算法加密
可以先使用 Jt808RequestFilter (需要配置jt808.features.request-filter.enabled=true)来修改请求体或响应体,可以实现请求和响应的加解密。
但是 Jt808RequestFilter 无法拦截 CommandSender 下发的指令消息。
由于之前没遇到过加解密的场景,一直没支持这个特性。 请提供几个加解密的示例性的调试报文(不方便公开的话群里私发我)。
最近太忙了,预计这周末或下周末提供加解密特性的支持。
感谢。 刚接到的需求,还在摸索,目前只有文档,还没有报文。 后续有动态,再同步。
我现在通过自定义 Jt808MsgEncoder,Jt808MsgDecoder 做了一套加解密的方案,和客户端联调数据是ok的,修改点和数据附上,博主可以审查下。
实现
-
CustomJt808MsgEncoderprivate CompositeByteBuf buildPackage(Jt808Response response, ByteBuf body, int totalSubPackageCount, int currentPackageNo, int flowId) { // 消息体sm4加密 body = sm4Encrypt(body); ByteBuf headerBuf = this.encodeMsgHeader(response, body, totalSubPackageCount > 0, totalSubPackageCount, currentPackageNo, flowId); ... } private ByteBuf encodeMsgHeader(Jt808Response response, ByteBuf body, boolean hasSubPackage, int totalSubPkgCount, int currentSubPkgNo, int flowId) { Jt808ProtocolVersion version = response.version(); ByteBuf header = this.allocator.buffer(); JtProtocolUtils.writeWord(header, response.msgId()); /* 加密类型,0b010 —bit10 --bit12为数据加密标识位; —当第 11位为 1,第10位和第12位为0,表示消息体经过SM4算法加密 */ int bodyPropsForJt808 = JtProtocolUtils.generateMsgBodyPropsForJt808(body.readableBytes(), 0b010, hasSubPackage, response.version(), response.reversedBit15InHeader()); ... } -
CustomJt808MsgDecoderpublic MutableJt808Request decode(ByteBuf byteBuf) { if (log.isDebugEnabled()) { log.debug("- >>>>>>>>>>>>>>> : 7E{}7E", HexStringUtils.byteBufToString(byteBuf)); } ByteBuf escaped = this.msgBytesProcessor.doEscapeForReceive(byteBuf); if (log.isDebugEnabled()) { log.debug("+ >>>>>>>>>>>>>>> : 7E{}7E", HexStringUtils.byteBufToString(escaped)); } Jt808RequestHeader header = this.parseMsgHeaderSpec(escaped); int msgBodyStartIndex = Jt808RequestHeader.msgBodyStartIndex(header.version(), header.msgBodyProps().hasSubPackage()); MsgType msgType = (MsgType)this.msgTypeParser.parseMsgType(header.msgId()).orElseThrow(() -> { JtProtocolUtils.release(new Object[]{escaped}); return new Jt808UnknownMsgException(header.msgId(), byteBuf); }); byte originalCheckSum = escaped.getByte(escaped.readableBytes() - 1); byte calculatedCheckSum = this.msgBytesProcessor.calculateCheckSum(escaped.slice(0, escaped.readableBytes() - 1)); ByteBuf body = escaped.retainedSlice(msgBodyStartIndex, header.msgBodyLength()); // 消息体 sm4 解密 body = sm4Decrypt(body); .... }
数据
- 终端注册 数据
.setProvinceId(11) .setCityId(2) .setManufacturerId("id987654321") .setTerminalType("type00123456781234567887654321") .setTerminalId("ID0000123456781234567887654321") .setColor((byte) 1) .setCarIdentifier("甘J-123459") - sm4 key
8e47374be6b8d114cb47be6a9a128a37,填充SM4/ECB/PKCS5Padding - 消息体加密后生成的报文
7E0100486001000000000000000006660001F54379B894A198DF648501D34446F71B043C33FBC988AA593AD96111482DD6DBBE8C573E551F2A2349D911536E9A033692A9C8F5A4DEC595738119DB95BECFA5FCCBFC9F4B1A5BA57FB43DDE36E28E6F7FAF5EA024C18DC3F2BEB4DCD247D4651D7E
升级到 2.1.4-rc.4(最新版 Jar 预计 24 小时内同步到中央仓库),然后提供一个 Jt808MsgEncryptionHandler 的实现即可,示例如下:
@Component
public class Jt808MsgEncryptionHandlerDemo01 implements Jt808MsgEncryptionHandler {
@Override
public ByteBuf decryptRequestBody(Jt808RequestHeader header, ByteBuf body) {
final int encryptionType = header.msgBodyProps().encryptionType();
if (encryptionType == 0) {
return body;
}
// @see https://github.com/hylexus/jt-framework/issues/82
// 消息属性中的 第10位,11位,12位 为 010 时,表示消息体经过SM4算法加密
if (encryptionType == 0b010) {
try {
return JtCryptoUtil.SM4.ecbDecrypt(getSecretKey(), body);
} finally {
JtProtocolUtils.release(body);
}
}
throw new NotImplementedException("不支持的加密类型: 0b" + FormatUtils.toBinaryString(encryptionType, 3));
}
@Override
public ByteBuf encryptResponseBody(Jt808Response response, ByteBuf plaintextBody) {
// response.encryptionType(010);
final int encryptionType = response.encryptionType();
if (encryptionType == 0) {
return plaintextBody;
}
// @see https://github.com/hylexus/jt-framework/issues/82
// 消息属性中的 第10位,11位,12位 为 010 时,表示消息体经过SM4算法加密
if (encryptionType == 0b010) {
try {
return JtCryptoUtil.SM4.ecbEncrypt(getSecretKey(), plaintextBody);
} finally {
JtProtocolUtils.release(plaintextBody);
}
}
throw new NotImplementedException("不支持的加密类型: 0b" + FormatUtils.toBinaryString(encryptionType, 3));
}
private byte[] getSecretKey() {
// 从其他配置中获取密钥
return HexStringUtils.hexString2Bytes("8e47374be6b8d114cb47be6a9a128a37");
}
}