2021-11-15 1.增加认证和加密通讯,未调通
| | |
| | | <?xml version="1.0" encoding="UTF-8"?>
|
| | | <project version="4">
|
| | | <component name="CompilerConfiguration">
|
| | | <bytecodeTargetLevel target="11" />
|
| | | <bytecodeTargetLevel target="1.8" />
|
| | | </component>
|
| | | </project> |
| | |
| | | </map>
|
| | | </option>
|
| | | </component>
|
| | | <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
| | | <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
| | | <output url="file://$PROJECT_DIR$/build/classes" />
|
| | | </component>
|
| | | <component name="ProjectType">
|
| | |
| | | import android.Manifest; |
| | | import android.app.Instrumentation; |
| | | import android.os.Bundle; |
| | | import android.util.Log; |
| | | import android.view.View; |
| | | import android.widget.TextView; |
| | | |
| | | import com.chad.library.adapter.base.BaseQuickAdapter; |
| | | import com.chad.library.adapter.base.listener.OnItemClickListener; |
| | | import com.google.gson.JsonObject; |
| | | import com.hdl.sdk.common.config.AuthenticateConfig; |
| | | import com.hdl.sdk.common.config.TopicConstant; |
| | | import com.hdl.sdk.common.utils.IdUtils; |
| | | import com.hdl.sdk.common.utils.IpUtils; |
| | | import com.hdl.sdk.connect.HDLAuthSocket; |
| | | import com.hdl.sdk.connect.HDLSocket; |
| | | import com.hdl.sdk.connect.bean.DeviceControlRequest; |
| | | import com.hdl.sdk.connect.bean.GatewaySearchBean; |
| | | import com.hdl.sdk.connect.bean.LinkRequest; |
| | | import com.hdl.sdk.connect.protocol.LinkMessageDecoder; |
| | | import com.hdl.sdk.connect.protocol.LinkMessageEncoder; |
| | |
| | | private RecyclerView rv; |
| | | private TextView tv; |
| | | private TextView responseTv; |
| | | |
| | | boolean isOn; |
| | | |
| | | |
| | | @Override |
| | |
| | | tv = findViewById(R.id.state_tv); |
| | | rv = findViewById(R.id.rv); |
| | | rv.setLayoutManager(new LinearLayoutManager(this)); |
| | | AuthenticateConfig.getInstance().setLocalEncrypt(true); |
| | | AuthenticateConfig.getInstance().setLocalSecret("5648d9b9cafd30dd"); |
| | | |
| | | ActivityResultLauncher<String[]> launcher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() { |
| | | @Override |
| | |
| | | beans.add(new DemoBean("设备控制")); |
| | | beans.add(new DemoBean("状态上报")); |
| | | beans.add(new DemoBean("读取状态")); |
| | | beans.add(new DemoBean("入网认证")); |
| | | demoAdapter = new DemoAdapter(beans); |
| | | rv.setAdapter(demoAdapter); |
| | | |
| | |
| | | break; |
| | | case 3: |
| | | //设备控制 |
| | | // HDLSocket.getInstance().propertyDown(); |
| | | isOn = !isOn; |
| | | List<DeviceControlRequest> requestList = new ArrayList<>(); |
| | | DeviceControlRequest request = new DeviceControlRequest(); |
| | | request.setSid("000101B847C71B02020100010101"); |
| | | List<DeviceControlRequest.StatusBean> statusBeanList= new ArrayList<>(); |
| | | DeviceControlRequest.StatusBean bean = new DeviceControlRequest.StatusBean(); |
| | | bean.setKey("on_off"); |
| | | bean.setValue(isOn ? "on" : "off"); |
| | | statusBeanList.add(bean); |
| | | request.setStatus(statusBeanList); |
| | | requestList.add(request); |
| | | HDLAuthSocket.getInstance().propertyDown(requestList,null); |
| | | |
| | | |
| | | break; |
| | | case 4: |
| | | //状态上报 |
| | |
| | | //读取状态 |
| | | // HDLSocket.getInstance().propertyRead(); |
| | | break; |
| | | case 6: |
| | | //入网认证 |
| | | HDLAuthSocket.getInstance().sendAuthenticateRequest(new HDLAuthSocket.CallBack() { |
| | | @Override |
| | | public void onError(String error) { |
| | | Log.i("TAG", "onError: 认证失败"); |
| | | // tv.setText("认证失败"); |
| | | // responseTv.setText(error); |
| | | } |
| | | |
| | | @Override |
| | | public void onSuccess(String data) { |
| | | tv.setText("认证成功"); |
| | | responseTv.setText(data); |
| | | } |
| | | }); |
| | | |
| | | // HDLAuthSocket.getInstance().searchGateway("1406844230123372545", new HDLAuthSocket.SearchGatewayCallBack() { |
| | | // @Override |
| | | // public void onEnd(String error) { |
| | | // |
| | | // } |
| | | // |
| | | // @Override |
| | | // public void onSuccess(GatewaySearchBean gatewaySearchBean) { |
| | | // Log.i("TAG", "onSuccess: 搜索成功:"+gatewaySearchBean.getGatewayId()); |
| | | // } |
| | | // }); |
| | | |
| | | |
| | | break; |
| | | } |
| | | } |
| | | }); |
New file |
| | |
| | | package com.hdl.sdk.common.config; |
| | | |
| | | import android.text.TextUtils; |
| | | |
| | | import com.hdl.sdk.common.utils.SPUtils; |
| | | |
| | | import static com.hdl.sdk.common.config.TopicConstant.DEIVCE_AUTH_REQUEST; |
| | | import static com.hdl.sdk.common.config.TopicConstant.GATEWAY_SEARCH; |
| | | |
| | | /** |
| | | * Created by jlchen on 11/11/21. |
| | | * |
| | | * @Description : AuthenticateConfig |
| | | */ |
| | | public class AuthenticateConfig { |
| | | private static final String Authenticate_LS_KEY = "auth_ls_key"; |
| | | private static final String AUTHENTICATE_GATEWAYID_KEY = "auth_gatewayid_key"; |
| | | private static final String AUTHENTICATE_IPADDRESS_KEY = "auth_ipaddress_key"; |
| | | |
| | | private String localSecret;//本地加密密钥 |
| | | private String gatewayId; |
| | | private String ipAddress; |
| | | private boolean isLocalEncrypt;//网关是否需要加密通讯 |
| | | |
| | | /** |
| | | * instance |
| | | */ |
| | | private volatile static AuthenticateConfig instance; |
| | | /** |
| | | * getInstance |
| | | * |
| | | * @return AuthenticateConfig |
| | | */ |
| | | public static synchronized AuthenticateConfig getInstance() { |
| | | if (instance == null) { |
| | | synchronized (AuthenticateConfig.class) { |
| | | if (instance == null) { |
| | | instance = new AuthenticateConfig(); |
| | | instance.loadConfig(); |
| | | } |
| | | } |
| | | } |
| | | return instance; |
| | | } |
| | | |
| | | /** |
| | | * 清空缓存 |
| | | */ |
| | | public void clearConfig() { |
| | | this.gatewayId = ""; |
| | | this.ipAddress = ""; |
| | | this.localSecret = ""; |
| | | SPUtils.remove(Authenticate_LS_KEY); |
| | | SPUtils.remove(AUTHENTICATE_GATEWAYID_KEY); |
| | | SPUtils.remove(AUTHENTICATE_IPADDRESS_KEY); |
| | | } |
| | | |
| | | /** |
| | | * 加载缓存 |
| | | */ |
| | | void loadConfig(){ |
| | | localSecret = SPUtils.getString(Authenticate_LS_KEY, ""); |
| | | } |
| | | |
| | | /** |
| | | * 保存配置 |
| | | * @param localSecret |
| | | * @param gatewayId |
| | | * @param ipAddress |
| | | */ |
| | | public void saveConfig(String localSecret, String gatewayId, String ipAddress) { |
| | | this.localSecret = localSecret; |
| | | this.gatewayId = gatewayId; |
| | | this.ipAddress = ipAddress; |
| | | SPUtils.put(Authenticate_LS_KEY, localSecret); |
| | | SPUtils.put(AUTHENTICATE_GATEWAYID_KEY, gatewayId); |
| | | SPUtils.put(AUTHENTICATE_IPADDRESS_KEY, ipAddress); |
| | | } |
| | | |
| | | /** |
| | | * 检测是否已经认证过 |
| | | * @return |
| | | */ |
| | | public boolean checkIfCertified(){ |
| | | //localSecret不为空并且长度等于16 |
| | | return !TextUtils.isEmpty(localSecret) && localSecret.length() == 16; |
| | | } |
| | | |
| | | public void setLocalSecret(String localSecret) { |
| | | this.localSecret = localSecret; |
| | | SPUtils.put(Authenticate_LS_KEY, localSecret); |
| | | } |
| | | |
| | | public String getLocalSecret() { |
| | | return localSecret; |
| | | } |
| | | |
| | | public String getGatewayId() { |
| | | return gatewayId; |
| | | } |
| | | |
| | | public String getIpAddress() { |
| | | return ipAddress; |
| | | } |
| | | |
| | | public boolean isLocalEncrypt() { |
| | | return isLocalEncrypt; |
| | | } |
| | | |
| | | public void setLocalEncrypt(boolean localEncrypt) { |
| | | isLocalEncrypt = localEncrypt; |
| | | } |
| | | |
| | | /** |
| | | * 判断当前主题数据是否需要加密 |
| | | * @param topicStr 当前主题 |
| | | * @return |
| | | */ |
| | | public boolean ifNeedEncrypt(String topicStr){ |
| | | //过滤相关需要加密的主题 |
| | | return (!topicStr.contains(DEIVCE_AUTH_REQUEST) //入网认证 |
| | | && !topicStr.contains(GATEWAY_SEARCH) //搜索网关主题 |
| | | && isLocalEncrypt//启用加密标志 |
| | | ); |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | */
|
| | | public class TopicConstant {
|
| | |
|
| | | //网关广播入网指令
|
| | | public static final String GATEWAY_AUTH_BROADCAST = "/user/all/custom/device/network_access/broadcast";
|
| | |
|
| | | //设备入网和认证
|
| | | public static final String DEIVCE_AUTH_REQUEST = "/user/all/custom/device/network_access/request";
|
| | |
|
| | | //设备入网和认证响应
|
| | | public static final String DEIVCE_AUTH_REQUEST_REPLY = "/user/all/custom/device/network_access/request_reply";
|
| | |
|
| | | //搜索网关
|
| | | public static final String GATEWAY_SEARCH = "/user/all/custom/gateway/search";
|
| | |
|
| | |
| | |
|
| | | }
|
| | |
|
| | | public static void e(String msg, Throwable tr) {
|
| | |
|
| | | }
|
| | |
|
| | | public static void w(String tag, String msg) {
|
| | |
|
| | | }
|
| | |
| | | api project(path: ':hdl-socket') |
| | | implementation 'androidx.appcompat:appcompat:1.2.0' |
| | | implementation 'com.google.android.material:material:1.3.0' |
| | | |
| | | //加密 |
| | | implementation 'cn.hutool:hutool-all:5.6.5' |
| | | implementation 'org.bouncycastle:bcprov-jdk15on:1.60' |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.connect; |
| | | |
| | | import android.text.TextUtils; |
| | | import android.util.Log; |
| | | |
| | | import com.google.gson.Gson; |
| | | import com.google.gson.JsonObject; |
| | | import com.google.gson.reflect.TypeToken; |
| | | import com.hdl.sdk.common.config.AuthenticateConfig; |
| | | import com.hdl.sdk.common.config.TopicConstant; |
| | | import com.hdl.sdk.common.utils.IdUtils; |
| | | import com.hdl.sdk.common.utils.IpUtils; |
| | | import com.hdl.sdk.common.utils.gson.GsonConvert; |
| | | import com.hdl.sdk.connect.bean.AuthenticateRequest; |
| | | import com.hdl.sdk.connect.bean.AuthenticateRequest.AuthenticateDeviceInfoBean; |
| | | import com.hdl.sdk.connect.bean.BaseLocalResponse; |
| | | import com.hdl.sdk.connect.bean.DeviceControlRequest; |
| | | import com.hdl.sdk.connect.bean.GatewaySearchBean; |
| | | import com.hdl.sdk.connect.bean.LinkRequest; |
| | | import com.hdl.sdk.connect.bean.LinkResponse; |
| | | import com.hdl.sdk.connect.protocol.LinkMessageDecoder; |
| | | import com.hdl.sdk.connect.protocol.LinkMessageEncoder; |
| | | import com.hdl.sdk.socket.SocketBoot; |
| | | import com.hdl.sdk.socket.SocketOptions; |
| | | import com.hdl.sdk.socket.client.UdpClient; |
| | | import com.hdl.sdk.socket.codec.MessagePipeLine; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.security.MessageDigest; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.util.List; |
| | | |
| | | import static com.hdl.sdk.common.config.TopicConstant.DEIVCE_AUTH_REQUEST; |
| | | |
| | | /** |
| | | * Created by jlchen on 11/11/21. |
| | | * |
| | | * @Description : HDLAuthSocket |
| | | */ |
| | | public class HDLAuthSocket { |
| | | /** |
| | | * udp默认端口 |
| | | */ |
| | | private static final int UDP_PORT = 8585; |
| | | private static SocketBoot updBoot; |
| | | /** |
| | | * instance |
| | | */ |
| | | private volatile static HDLAuthSocket instance; |
| | | |
| | | public interface CallBack { |
| | | |
| | | void onError(String error); |
| | | |
| | | void onSuccess(String data); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * getInstance |
| | | * |
| | | * @return HDLAuthSocket |
| | | */ |
| | | public static synchronized HDLAuthSocket getInstance() { |
| | | if (instance == null) { |
| | | synchronized (AuthenticateConfig.class) { |
| | | if (instance == null) { |
| | | instance = new HDLAuthSocket(); |
| | | } |
| | | } |
| | | } |
| | | return instance; |
| | | } |
| | | |
| | | private SocketOptions getUdpOptions() { |
| | | final SocketOptions options = new SocketOptions(); |
| | | final MessagePipeLine pipeLine = new MessagePipeLine(); |
| | | pipeLine.add(new LinkMessageDecoder()); |
| | | pipeLine.add(new LinkMessageEncoder()); |
| | | options.setHandleMessage(pipeLine); |
| | | options.setEnabledHeartbeat(false); |
| | | return options; |
| | | } |
| | | |
| | | private SocketBoot getUdpBoot(String ip) { |
| | | if (updBoot == null) { |
| | | updBoot = UdpClient.init(ip, UDP_PORT, getUdpOptions()); |
| | | updBoot.connect(); |
| | | } |
| | | return updBoot; |
| | | } |
| | | |
| | | private String getOid() { |
| | | return "000101EA9B8C1C22"; |
| | | } |
| | | |
| | | private String getSid() { |
| | | return "000101EA9B8C1C2202010001021A"; |
| | | } |
| | | |
| | | /** |
| | | * 发送入网及认证请求 |
| | | * |
| | | * @param ip 网关IP |
| | | * @param request 认证请求信息 |
| | | * @param callBack 结果回调 |
| | | */ |
| | | public void sendAuthenticateRequest(String ip, AuthenticateRequest request, CallBack callBack) { |
| | | if (request == null) { |
| | | callBack.onError("request null"); |
| | | } |
| | | String topic = DEIVCE_AUTH_REQUEST; |
| | | Gson gs = new Gson(); |
| | | String requestStr = gs.toJson(request); |
| | | LinkRequest message = new LinkRequest(topic, requestStr); |
| | | |
| | | HdlSocketHelper.send(getUdpBoot(ip), message, new HdlSocketHelper.HdlSocketListener() { |
| | | @Override |
| | | public void onSucceed(Object msg) { |
| | | callBack.onSuccess(msg.toString()); |
| | | } |
| | | |
| | | @Override |
| | | public void onFailure() { |
| | | Log.i("TAG", "onFailure: "); |
| | | callBack.onError("超时"); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 发送入网及认证请求 |
| | | * |
| | | * @param callBack 结果回调 |
| | | */ |
| | | public void sendAuthenticateRequest(CallBack callBack) { |
| | | String macStr = "AA000000000000BB"; |
| | | String secret = "87ae414b7a853f65"; |
| | | String mac_key = stringToMD5(stringToMD5(macStr + secret)); |
| | | |
| | | String versionString = "HDL_V1.0.1"; |
| | | String time = String.valueOf(System.currentTimeMillis()); |
| | | |
| | | //1.设置认证信息 |
| | | AuthenticateRequest.RequestBean requestBean = new AuthenticateRequest.RequestBean(); |
| | | requestBean.setMAC(macStr); |
| | | requestBean.setSupplier("HDL"); |
| | | requestBean.setFirmwareVersion(versionString); |
| | | requestBean.setHardwareModel("1956F"); |
| | | AuthenticateRequest.AuthBean authbean = new AuthenticateRequest.AuthBean(); |
| | | authbean.setSpk("ir.module"); |
| | | authbean.setMACKey(mac_key); |
| | | authbean.setRequest(requestBean); |
| | | |
| | | |
| | | //2.设置设备信息 |
| | | AuthenticateDeviceInfoBean infoBean = new AuthenticateDeviceInfoBean(); |
| | | infoBean.setDeviceMAC(macStr); |
| | | infoBean.setIPMAC(macStr); |
| | | infoBean.setDeviceName("HDL面板"); |
| | | infoBean.setAccessMode("HDL"); |
| | | infoBean.setOID(getOid()); |
| | | infoBean.setSid(getSid()); |
| | | // infoBean.set |
| | | AuthenticateRequest.VersionBean[] versionBeans = new AuthenticateRequest.VersionBean[]{new AuthenticateRequest.VersionBean("FW", versionString), new AuthenticateRequest.VersionBean("HW", "1956F")}; |
| | | infoBean.setVersions(versionBeans); |
| | | AuthenticateRequest request = new AuthenticateRequest(IdUtils.getUUId(), time, infoBean, authbean); |
| | | |
| | | String ip = IpUtils.getBroadcastAddress(); |
| | | ip = "192.168.10.102"; |
| | | sendAuthenticateRequest(ip, request, callBack); |
| | | } |
| | | |
| | | public interface SearchGatewayCallBack { |
| | | /** |
| | | * 搜索结束 |
| | | * |
| | | * @param error |
| | | */ |
| | | void onEnd(String error); |
| | | |
| | | /** |
| | | * 搜索网关成功 |
| | | * |
| | | * @param gatewaySearchBean |
| | | */ |
| | | void onSuccess(GatewaySearchBean gatewaySearchBean); |
| | | } |
| | | |
| | | /** |
| | | * 开始搜索所有网关,有网关回复就回调,上层自己做去重判断 |
| | | * |
| | | * @param callBack 回调 |
| | | */ |
| | | public void startSearchAllGateway(SearchGatewayCallBack callBack) { |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 暂停搜索网关 |
| | | */ |
| | | public void endSearchAllGateway() { |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 搜索指定网关是否在线,搜索到则返回指定的网关对象 |
| | | * |
| | | * @param gatewayId 网关id |
| | | * @param callBack 回调 |
| | | */ |
| | | public void searchGateway(String gatewayId, SearchGatewayCallBack callBack) { |
| | | String time = String.valueOf(System.currentTimeMillis()); |
| | | JsonObject jsonObject = new JsonObject(); |
| | | jsonObject.addProperty("id", IdUtils.getUUId()); |
| | | jsonObject.addProperty("time_stamp", time); |
| | | String ip = IpUtils.getBroadcastAddress(); |
| | | LinkRequest message = new LinkRequest(TopicConstant.GATEWAY_SEARCH, |
| | | jsonObject.toString()); |
| | | |
| | | HdlSocketHelper.send(getUdpBoot(ip), message, new HdlSocketHelper.HdlSocketListener() { |
| | | @Override |
| | | public void onSucceed(Object msg) { |
| | | GatewaySearchBean searchBean = getGatewaySearchBean(msg); |
| | | if (searchBean != null && searchBean.getGatewayId() == gatewayId) { |
| | | Log.i("TAG", "onSuccess: "); |
| | | callBack.onSuccess(searchBean); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void onFailure() { |
| | | Log.i("TAG", "onFailure: "); |
| | | callBack.onEnd("超时"); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | private GatewaySearchBean getGatewaySearchBean(Object msg) { |
| | | GatewaySearchBean searchBean = null; |
| | | if (msg instanceof LinkResponse) { |
| | | LinkResponse linkResponse = (LinkResponse) msg; |
| | | String data = linkResponse.getData(); |
| | | if (!TextUtils.isEmpty(data)) { |
| | | final BaseLocalResponse<GatewaySearchBean> response = GsonConvert.getGson().fromJson(data, new TypeToken<BaseLocalResponse<GatewaySearchBean>>() { |
| | | }.getType()); |
| | | searchBean = response.getObjects(); |
| | | } |
| | | |
| | | } |
| | | return searchBean; |
| | | } |
| | | |
| | | /** |
| | | * 设备控制 |
| | | */ |
| | | public void propertyDown(List<DeviceControlRequest> request, HDLSocket.CallBack callBack) { |
| | | |
| | | // if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) { |
| | | String time = String.valueOf(System.currentTimeMillis()); |
| | | |
| | | final BaseLocalResponse<List<DeviceControlRequest>> data = new BaseLocalResponse<>(); |
| | | data.setId(IdUtils.getUUId()); |
| | | data.setTime_stamp(time); |
| | | data.setObjects(request); |
| | | |
| | | |
| | | String topic = String.format(TopicConstant.PROPERTY_DOWN, "1406844230123372545"); |
| | | LinkRequest message = new LinkRequest(topic, |
| | | GsonConvert.getGson().toJson(request)); |
| | | |
| | | Log.i("TAG", "propertyDown: " + message.getData()); |
| | | |
| | | String ip = IpUtils.getBroadcastAddress(); |
| | | HdlSocketHelper.send(getUdpBoot(ip), message, null); |
| | | |
| | | // } |
| | | } |
| | | |
| | | String stringToMD5(String text) { |
| | | byte[] hash; |
| | | try { |
| | | hash = MessageDigest.getInstance("MD5").digest(text.getBytes("UTF-8")); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | e.printStackTrace(); |
| | | return null; |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | return null; |
| | | } |
| | | |
| | | StringBuilder hex = new StringBuilder(hash.length * 2); |
| | | for (byte b : hash) { |
| | | if ((b & 0xFF) < 0x10) |
| | | hex.append("0"); |
| | | hex.append(Integer.toHexString(b & 0xFF)); |
| | | } |
| | | |
| | | return hex.toString(); |
| | | } |
| | | |
| | | } |
| | |
| | | import com.hdl.sdk.common.utils.SPUtils;
|
| | | import com.hdl.sdk.common.utils.ThreadToolUtils;
|
| | | import com.hdl.sdk.common.utils.gson.GsonConvert;
|
| | | import com.hdl.sdk.connect.bean.AuthenticateRequest;
|
| | | import com.hdl.sdk.connect.bean.BaseLocalRequest;
|
| | | import com.hdl.sdk.connect.bean.BaseLocalResponse;
|
| | | import com.hdl.sdk.connect.bean.DeviceControlRequest;
|
| | |
| | | * 组播搜索
|
| | | */
|
| | | public void searchGateway(CallBack callBack) {
|
| | | gatewayId = "";//重置网关ID
|
| | | this.searchCallBack = callBack;
|
| | |
|
| | | if (searchGatewayThread != null) {
|
| | |
| | |
|
| | | String replyTopic = String.format(TopicConstant.PROPERTY_DOWN_REPLY, getGatewayId());
|
| | | try {
|
| | | sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
|
| | | sendMsg(message.getSendBytes(), replyTopic, callBack, new SendListener() {
|
| | | @Override
|
| | | public void onSucceed() {
|
| | |
|
| | |
| | | }
|
| | | }
|
| | | });
|
| | | } catch (UnsupportedEncodingException e) {
|
| | | } catch (Exception e) {
|
| | | if (callBack != null) {
|
| | | callBack.onError("控制指令发送失败");
|
| | | }
|
New file |
| | |
| | | package com.hdl.sdk.connect;
|
| | |
|
| | | import android.text.TextUtils;
|
| | |
|
| | | import com.hdl.sdk.common.event.EventDispatcher;
|
| | | import com.hdl.sdk.common.event.EventListener;
|
| | | import com.hdl.sdk.common.utils.ThreadToolUtils;
|
| | | import com.hdl.sdk.connect.bean.LinkRequest;
|
| | | import com.hdl.sdk.socket.SocketBoot;
|
| | |
|
| | | import java.util.concurrent.ScheduledExecutorService;
|
| | | import java.util.concurrent.TimeUnit;
|
| | | import java.util.concurrent.atomic.AtomicBoolean;
|
| | | import java.util.concurrent.atomic.AtomicInteger;
|
| | |
|
| | | /**
|
| | | * Created by Tong on 2021/11/11.
|
| | | */
|
| | | public class HdlSocketHelper {
|
| | |
|
| | | private static final Long DEF_SEND_TIMEOUT = 1000L;
|
| | | private static final int DEF_MAX_RETRY = 4;
|
| | | private static final int DEF_SEND_ONE = 1;
|
| | |
|
| | | private final Long sendAwaitTime;
|
| | | private final int maxRetry;
|
| | |
|
| | | private final SocketBoot boot;
|
| | | private final LinkRequest linkRequest;
|
| | | private final EventListener eventListener;
|
| | |
|
| | | private final AtomicInteger sendNumber;
|
| | |
|
| | | private final AtomicBoolean isSend = new AtomicBoolean();
|
| | |
|
| | | private final HdlSocketListener listener;
|
| | |
|
| | | private ScheduledExecutorService sendThread;
|
| | |
|
| | | public interface HdlSocketListener {
|
| | | void onSucceed(Object msg);
|
| | |
|
| | | void onFailure();
|
| | | }
|
| | |
|
| | | private HdlSocketHelper(Long sendAwaitTime, int maxRetry, SocketBoot boot, LinkRequest linkRequest, String observeTopic, HdlSocketListener listener) {
|
| | | this.sendAwaitTime = sendAwaitTime;
|
| | | this.maxRetry = maxRetry;
|
| | | this.boot = boot;
|
| | | this.linkRequest = linkRequest;
|
| | | this.listener = listener;
|
| | | this.sendNumber = new AtomicInteger(0);
|
| | | eventListener = new EventListener() {
|
| | | @Override
|
| | | public void onMessage(Object msg) {
|
| | | isSend.set(true);
|
| | | if (listener != null) {
|
| | | listener.onSucceed(msg);
|
| | | }
|
| | | if (sendThread != null) {
|
| | | sendThread.shutdownNow();
|
| | | }
|
| | | EventDispatcher.getInstance().remove(eventListener);
|
| | | }
|
| | | };
|
| | | EventDispatcher.getInstance().register(observeTopic, eventListener);
|
| | | }
|
| | |
|
| | | public static void send(SocketBoot boot, LinkRequest linkRequest, String observeTopic, HdlSocketListener listener, Long sendAwaitTime, int maxRetry) {
|
| | | if (TextUtils.isEmpty(observeTopic)) {
|
| | | observeTopic = linkRequest.getTopic() + "_reply";
|
| | | }
|
| | | HdlSocketHelper socketHelper = new HdlSocketHelper(sendAwaitTime, maxRetry, boot, linkRequest, observeTopic, listener);
|
| | | socketHelper.resend();
|
| | | }
|
| | |
|
| | | public static void send(SocketBoot boot, LinkRequest linkRequest, String observeTopic, HdlSocketListener listener) {
|
| | | send(boot, linkRequest, observeTopic, listener, DEF_SEND_TIMEOUT, DEF_MAX_RETRY);
|
| | | }
|
| | |
|
| | |
|
| | | public static void send(SocketBoot boot, LinkRequest linkRequest, HdlSocketListener listener) {
|
| | | send(boot, linkRequest, "", listener, DEF_SEND_TIMEOUT, DEF_MAX_RETRY);
|
| | | }
|
| | |
|
| | | public static void sendOne(SocketBoot boot, LinkRequest linkRequest, HdlSocketListener listener) {
|
| | | send(boot, linkRequest, "", listener, DEF_SEND_TIMEOUT, DEF_SEND_ONE);
|
| | | }
|
| | |
|
| | | private void resend() {
|
| | | getSendThread().scheduleWithFixedDelay(new Runnable() {
|
| | | @Override
|
| | | public void run() {
|
| | | if ((sendNumber.get() < maxRetry + 2) || !isSend.get()) {
|
| | | try {
|
| | | if (sendNumber.get() < maxRetry + 1) {
|
| | | if (boot != null) {
|
| | | boot.sendMsg(linkRequest.getSendBytes());
|
| | | }
|
| | | sendNumber.set(sendNumber.get() + 1);
|
| | | } else {
|
| | | notifyFailure();
|
| | | }
|
| | | } catch (Exception e) {
|
| | | e.printStackTrace();
|
| | | sendNumber.set(sendNumber.get() + 1);
|
| | | } finally {
|
| | | if (sendNumber.get() > maxRetry + 1 && !isSend.get()) {
|
| | | notifyFailure();
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | | }, sendAwaitTime, sendAwaitTime, TimeUnit.MILLISECONDS);
|
| | | }
|
| | |
|
| | | public ScheduledExecutorService getSendThread() {
|
| | | if (sendThread == null) {
|
| | | sendThread = ThreadToolUtils.getInstance().newScheduledThreadPool(1);
|
| | | }
|
| | | return sendThread;
|
| | | }
|
| | |
|
| | |
|
| | | private void notifyFailure() {
|
| | | if (sendThread != null) {
|
| | | sendThread.shutdownNow();
|
| | | }
|
| | | if (listener != null) {
|
| | | listener.onFailure();
|
| | | }
|
| | | }
|
| | | }
|
New file |
| | |
| | | package com.hdl.sdk.connect.bean; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * Created by jlchen on 11/11/21. |
| | | * |
| | | * @Description : AuthenticateRequest |
| | | * 三方网络设备入网及认证 请求参数 |
| | | * 请求topic:/user/all/custom/deivce/network_access/request |
| | | */ |
| | | public class AuthenticateRequest implements Serializable { |
| | | private String id; |
| | | private String time_stamp; |
| | | private AuthenticateDeviceInfoBean objects;//当前设备基本信息 |
| | | private AuthBean auth;//认证信息 |
| | | |
| | | public String getID() { return id; } |
| | | public void setID(String value) { this.id = value; } |
| | | |
| | | public String getTimeStamp() { return time_stamp; } |
| | | public void setTimeStamp(String value) { this.time_stamp = value; } |
| | | |
| | | public AuthenticateDeviceInfoBean getObjects() { return objects; } |
| | | public void setObjects(AuthenticateDeviceInfoBean value) { this.objects = value; } |
| | | |
| | | public AuthBean getAuth() { return auth; } |
| | | public void setAuth(AuthBean value) { this.auth = value; } |
| | | |
| | | public AuthenticateRequest(String id, String time_stamp, AuthenticateDeviceInfoBean objects, AuthBean auth) { |
| | | this.id = id; |
| | | this.time_stamp = time_stamp; |
| | | this.objects = objects; |
| | | this.auth = auth; |
| | | } |
| | | |
| | | public static class AuthBean implements Serializable { |
| | | private String mac_key;//(mac+secret)的两次md5值 |
| | | private String spk;//(mac+secret)的两次md5值 |
| | | private RequestBean request;//设备相关信息 |
| | | |
| | | public String getMACKey() { return mac_key; } |
| | | public void setMACKey(String value) { this.mac_key = value; } |
| | | |
| | | public String getSpk() { return spk; } |
| | | public void setSpk(String value) { this.spk = value; } |
| | | |
| | | public RequestBean getRequest() { return request; } |
| | | public void setRequest(RequestBean value) { this.request = value; } |
| | | |
| | | public AuthBean() { |
| | | |
| | | } |
| | | public AuthBean(String mac_key, String spk, RequestBean request) { |
| | | this.mac_key = mac_key; |
| | | this.spk = spk; |
| | | this.request = request; |
| | | } |
| | | } |
| | | |
| | | public static class RequestBean implements Serializable{ |
| | | private String mac;//设备mac |
| | | private String supplier;//厂家 |
| | | private String hardware_model;//设备型号 |
| | | private String firmware_version;//程序版本 |
| | | public RequestBean(){}; |
| | | public RequestBean(String mac, String supplier, String hardware_model, String firmware_version) { |
| | | this.mac = mac; |
| | | this.supplier = supplier; |
| | | this.hardware_model = hardware_model; |
| | | this.firmware_version = firmware_version; |
| | | } |
| | | |
| | | public String getMAC() { return mac; } |
| | | public void setMAC(String value) { this.mac = value; } |
| | | |
| | | public String getSupplier() { return supplier; } |
| | | public void setSupplier(String value) { this.supplier = value; } |
| | | |
| | | public String getHardwareModel() { return hardware_model; } |
| | | public void setHardwareModel(String value) { this.hardware_model = value; } |
| | | |
| | | public String getFirmwareVersion() { return firmware_version; } |
| | | public void setFirmwareVersion(String value) { this.firmware_version = value; } |
| | | } |
| | | |
| | | public static class AuthenticateDeviceInfoBean implements Serializable{ |
| | | private String oid;//设备的Oid |
| | | private String device_mac;//设备的Mac |
| | | private String device_name;// |
| | | private String device_model; |
| | | private String access_mode = "WIFI"; |
| | | private String sid; |
| | | private String ip_mac; |
| | | private String ip_address = "192.16.10.104"; |
| | | private String netmask = "255.255.255.0"; |
| | | private String ip_gateway = "192.16.10.1"; |
| | | private String dns1 = "114.114.114.114"; |
| | | private String dns2 = "8.8.8.8"; |
| | | private VersionBean[] versions; |
| | | |
| | | public String getOID() { return oid; } |
| | | public void setOID(String value) { this.oid = value; } |
| | | |
| | | public String getDeviceMAC() { return device_mac; } |
| | | public void setDeviceMAC(String value) { this.device_mac = value; } |
| | | |
| | | public String getDeviceName() { return device_name; } |
| | | public void setDeviceName(String value) { this.device_name = value; } |
| | | |
| | | public String getDeviceModel() { return device_model; } |
| | | public void setDeviceModel(String value) { this.device_model = value; } |
| | | |
| | | public String getAccessMode() { return access_mode; } |
| | | public void setAccessMode(String value) { this.access_mode = value; } |
| | | |
| | | public String getSid() { return sid; } |
| | | public void setSid(String value) { this.sid = value; } |
| | | |
| | | public String getIPMAC() { return ip_mac; } |
| | | public void setIPMAC(String value) { this.ip_mac = value; } |
| | | |
| | | public String getIPAddress() { return ip_address; } |
| | | public void setIPAddress(String value) { this.ip_address = value; } |
| | | |
| | | public String getNetmask() { return netmask; } |
| | | public void setNetmask(String value) { this.netmask = value; } |
| | | |
| | | public String getIPGateway() { return ip_gateway; } |
| | | public void setIPGateway(String value) { this.ip_gateway = value; } |
| | | |
| | | public String getDns1() { return dns1; } |
| | | public void setDns1(String value) { this.dns1 = value; } |
| | | |
| | | public String getDns2() { return dns2; } |
| | | public void setDns2(String value) { this.dns2 = value; } |
| | | |
| | | public VersionBean[] getVersions() { return versions; } |
| | | public void setVersions(VersionBean[] value) { this.versions = value; } |
| | | } |
| | | |
| | | public static class VersionBean implements Serializable{ |
| | | private String module; |
| | | private String version; |
| | | |
| | | public VersionBean(String module, String version) { |
| | | this.module = module; |
| | | this.version = version; |
| | | } |
| | | |
| | | public String getModule() { |
| | | return module; |
| | | } |
| | | |
| | | public void setModule(String value) { |
| | | this.module = value; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.connect.bean; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * Created by jlchen on 11/12/21. |
| | | * |
| | | * @Description : AuthenticateResponseBean |
| | | */ |
| | | public class AuthenticateResponseBean implements Serializable { |
| | | private String id; |
| | | private String timeStamp; |
| | | private String code; |
| | | private GatewayObjects objects; |
| | | private Auth auth; |
| | | |
| | | public String getID() { return id; } |
| | | public void setID(String value) { this.id = value; } |
| | | |
| | | public String getTimeStamp() { return timeStamp; } |
| | | public void setTimeStamp(String value) { this.timeStamp = value; } |
| | | |
| | | public String getCode() { return code; } |
| | | public void setCode(String value) { this.code = value; } |
| | | |
| | | public GatewayObjects getObjects() { return objects; } |
| | | public void setObjects(GatewayObjects value) { this.objects = value; } |
| | | |
| | | public Auth getAuth() { return auth; } |
| | | public void setAuth(Auth value) { this.auth = value; } |
| | | |
| | | public class Auth implements Serializable { |
| | | private String localSecret; |
| | | |
| | | public String getLocalSecret() { return localSecret; } |
| | | public void setLocalSecret(String value) { this.localSecret = value; } |
| | | } |
| | | |
| | | public class GatewayObjects implements Serializable { |
| | | private String ip_address; |
| | | private String gatewayId; |
| | | private String oid; |
| | | |
| | | public String getIPAddress() { return ip_address; } |
| | | public void setIPAddress(String value) { this.ip_address = value; } |
| | | |
| | | public String getGatewayID() { return gatewayId; } |
| | | public void setGatewayID(String value) { this.gatewayId = value; } |
| | | |
| | | public String getOID() { return oid; } |
| | | public void setOID(String value) { this.oid = value; } |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | private String ip_address;
|
| | | private String access_mode;
|
| | | private String master;
|
| | | private boolean isLocalEncrypt;//2021-11-11 新增
|
| | |
|
| | | public String getDevice_model() {
|
| | | return device_model;
|
| | |
| | | public void setMaster(String master) {
|
| | | this.master = master;
|
| | | }
|
| | |
|
| | | public boolean isLocalEncrypt() {
|
| | | return isLocalEncrypt;
|
| | | }
|
| | |
|
| | | public void setLocalEncrypt(boolean localEncrypt) {
|
| | | isLocalEncrypt = localEncrypt;
|
| | | }
|
| | | }
|
| | |
| | | package com.hdl.sdk.connect.bean;
|
| | |
|
| | | import android.text.TextUtils;
|
| | | import android.util.Log;
|
| | |
|
| | | import androidx.annotation.NonNull;
|
| | |
|
| | | import com.hdl.sdk.common.config.AuthenticateConfig;
|
| | | import com.hdl.sdk.connect.utils.AESUtils;
|
| | | import com.hdl.sdk.connect.utils.AesUtil;
|
| | |
|
| | | import java.io.UnsupportedEncodingException;
|
| | |
|
| | | import static com.hdl.sdk.common.config.TopicConstant.DEIVCE_AUTH_REQUEST;
|
| | | import static com.hdl.sdk.common.config.TopicConstant.GATEWAY_SEARCH;
|
| | |
|
| | | /**
|
| | | * Created by Tong on 2021/9/29.
|
| | |
| | | public class LinkRequest {
|
| | | private String topic;
|
| | | private String data;
|
| | |
|
| | | private int length;
|
| | |
|
| | | public LinkRequest() {
|
| | |
| | | public void setData(String data) {
|
| | | this.data = data;
|
| | | if (!TextUtils.isEmpty(data)) {
|
| | | setLength(data.length());
|
| | | setLength(getBytesLength(data));
|
| | | // setLength(data.length());
|
| | | } else {
|
| | | setLength(0);
|
| | | }
|
| | |
| | | "\r\n\r\n" +
|
| | | getData();
|
| | | }
|
| | |
|
| | | private static byte[] stringToBytes(String str) {
|
| | | try {
|
| | | // 使用指定的字符集将此字符串编码为byte序列并存到一个byte数组中
|
| | | return str.getBytes("utf-8");
|
| | | } catch (UnsupportedEncodingException e) {
|
| | | e.printStackTrace();
|
| | | }
|
| | | return new byte[]{};
|
| | | }
|
| | |
|
| | | private int getBytesLength(String str){
|
| | | return stringToBytes(str).length;
|
| | | }
|
| | |
|
| | | /**
|
| | | * 合并数组
|
| | | * @param bt1
|
| | | * @param bt2
|
| | | * @return
|
| | | */
|
| | | public static byte[] byteMerger(byte[] bt1, byte[] bt2){
|
| | | byte[] bt3 = new byte[bt1.length + bt2.length];
|
| | | System.arraycopy(bt1, 0, bt3, 0, bt1.length);
|
| | | System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
|
| | | return bt3;
|
| | | }
|
| | | /**
|
| | | * 获取发送数据byte
|
| | | *
|
| | | * @return
|
| | | */
|
| | | public byte[] getSendBytes() {
|
| | | try {
|
| | | //判断是否需要加密
|
| | | if (AuthenticateConfig.getInstance().ifNeedEncrypt(topic)) {
|
| | | //需要加密
|
| | | byte[] dataBytes = AesUtil.aesEncrypt(stringToBytes(data), AuthenticateConfig.getInstance().getLocalSecret());
|
| | | String headString = "Topic:" + getTopic() + "\r\n" + "Length:" + dataBytes.length + "\r\n" + "\r\n";
|
| | | // byte[] headBytes = headString.getBytes("utf-8");
|
| | | byte[] headBytes = headString.getBytes();
|
| | | byte[] sendBytes = byteMerger(headBytes, dataBytes);
|
| | | return sendBytes;
|
| | | } else {
|
| | | return this.toString().getBytes("utf-8");
|
| | | }
|
| | |
|
| | | } catch (Exception e) {
|
| | | return new byte[]{};
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | package com.hdl.sdk.connect.protocol;
|
| | |
|
| | |
|
| | | import android.util.Log;
|
| | |
|
| | | import com.hdl.sdk.common.config.AuthenticateConfig;
|
| | | import com.hdl.sdk.common.event.EventDispatcher;
|
| | | import com.hdl.sdk.common.utils.ByteUtils;
|
| | | import com.hdl.sdk.connect.bean.LinkResponse;
|
| | | import com.hdl.sdk.connect.utils.AesUtil;
|
| | | import com.hdl.sdk.connect.utils.ProtocolParse;
|
| | | import com.hdl.sdk.socket.codec.ByteToMessageDecoder;
|
| | |
|
| | |
| | | if (bodyLength > 0) {
|
| | | if (byteArray.length >= bodyLength + bodyStartIndex) {
|
| | | byte[] body = ByteUtils.getRangeBytes(bytes, bodyStartIndex, bodyStartIndex + bodyLength);
|
| | |
|
| | | if(AuthenticateConfig.getInstance().ifNeedEncrypt(response.getTopic())){
|
| | | //需要解密
|
| | | byte[] bodyBytes = AesUtil.aesDecrypt(body,AuthenticateConfig.getInstance().getLocalSecret());
|
| | | response.setData(new String(bodyBytes, "utf-8"));
|
| | | Log.i("TAG", "decoder: ");
|
| | | }else{
|
| | | response.setData(new String(body, "utf-8"));
|
| | | }
|
| | |
|
| | |
|
| | |
|
| | | if (byteArray.length >= bodyLength + bodyStartIndex) {
|
| | | //保存余留
|
| | |
| | | protected byte[] encode(byte[] data) throws Exception {
|
| | | return data;
|
| | | }
|
| | |
|
| | | }
|
New file |
| | |
| | | package com.hdl.sdk.connect.utils;
|
| | |
|
| | | import android.util.Base64;
|
| | |
|
| | | import java.io.UnsupportedEncodingException;
|
| | | import java.security.InvalidAlgorithmParameterException;
|
| | | import java.security.InvalidKeyException;
|
| | | import java.security.NoSuchAlgorithmException;
|
| | |
|
| | | import javax.crypto.BadPaddingException;
|
| | | import javax.crypto.Cipher;
|
| | | import javax.crypto.IllegalBlockSizeException;
|
| | | import javax.crypto.NoSuchPaddingException;
|
| | | import javax.crypto.spec.IvParameterSpec;
|
| | | import javax.crypto.spec.SecretKeySpec;
|
| | |
|
| | | /**
|
| | | * Created by Tong on 2021/11/3.
|
| | | */
|
| | | public class AESUtils {
|
| | |
|
| | | public static String encryptAES(String content, String key) throws NoSuchPaddingException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException {
|
| | | return encryptAES(content, key, "");
|
| | | }
|
| | |
|
| | | public static String encryptAES(String content, String key, String ivString)
|
| | | throws InvalidKeyException, NoSuchAlgorithmException,
|
| | | NoSuchPaddingException, UnsupportedEncodingException,
|
| | | InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
|
| | | byte[] byteContent = content.getBytes("UTF-8");
|
| | | byte[] encryptedBytes = encryptAES(byteContent,key,ivString);
|
| | | return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP);
|
| | | }
|
| | |
|
| | | public static byte[] encryptAES(byte[] byteContent, String key) throws NoSuchPaddingException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException {
|
| | | return encryptAES(byteContent, key, key);
|
| | | }
|
| | |
|
| | | public static byte[] encryptAES(byte[] byteContent, String key, String ivString)
|
| | | throws InvalidKeyException, NoSuchAlgorithmException,
|
| | | NoSuchPaddingException, UnsupportedEncodingException,
|
| | | InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
|
| | |
|
| | | byte[] enCodeFormat = key.getBytes();
|
| | | SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
|
| | |
|
| | | byte[] initParam = ivString.getBytes();
|
| | | IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
|
| | |
|
| | | // 指定加密的算法、工作模式和填充方式
|
| | | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
| | | cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
|
| | |
|
| | | byte[] encryptedBytes = cipher.doFinal(byteContent);
|
| | | return encryptedBytes;
|
| | | }
|
| | |
|
| | | public static String decryptAES(String content, String key) throws NoSuchPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
|
| | | return decryptAES(content, key, "");
|
| | | }
|
| | |
|
| | | public static String decryptAES(String content, String key, String ivString)
|
| | | throws InvalidKeyException, NoSuchAlgorithmException,
|
| | | NoSuchPaddingException, InvalidAlgorithmParameterException,
|
| | | IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
|
| | |
|
| | |
|
| | | // base64 解码
|
| | | byte[] encryptedBytes = Base64.decode(content, Base64.NO_WRAP);
|
| | |
|
| | | byte[] enCodeFormat = key.getBytes();
|
| | | SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, "AES");
|
| | |
|
| | | byte[] initParam = ivString.getBytes();
|
| | | IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
|
| | |
|
| | | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
| | | cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
|
| | |
|
| | | byte[] result = cipher.doFinal(encryptedBytes);
|
| | |
|
| | | return new String(result, "UTF-8");
|
| | | }
|
| | |
|
| | | }
|
| | |
|
New file |
| | |
| | | package com.hdl.sdk.connect.utils; |
| | | |
| | | |
| | | import com.hdl.sdk.common.utils.LogUtils; |
| | | |
| | | import org.bouncycastle.jce.provider.BouncyCastleProvider; |
| | | |
| | | import java.security.InvalidAlgorithmParameterException; |
| | | import java.security.InvalidKeyException; |
| | | import java.security.Key; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.security.Security; |
| | | |
| | | import javax.crypto.BadPaddingException; |
| | | import javax.crypto.Cipher; |
| | | import javax.crypto.IllegalBlockSizeException; |
| | | import javax.crypto.NoSuchPaddingException; |
| | | import javax.crypto.spec.IvParameterSpec; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | |
| | | import cn.hutool.core.util.HexUtil; |
| | | |
| | | /** |
| | | * Aes 加解密工具类 |
| | | * |
| | | * @author yangtao |
| | | * 2020年10月29日 |
| | | */ |
| | | public class AesUtil { |
| | | |
| | | private static final String CIPHER_INSTANCE = "AES/ECB/PKCS5Padding"; |
| | | private static final String AES_ALGORITHM = "AES"; |
| | | |
| | | static { |
| | | //AES/CBC/PKCS7Padding 依赖 |
| | | Security.addProvider(new BouncyCastleProvider()); |
| | | } |
| | | |
| | | /** |
| | | * AES加密 |
| | | * |
| | | * @param key |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public static byte[] aesEncrypt(byte[] content, String key) { |
| | | return encrypt(content, key.getBytes(), "AES/CBC/PKCS7Padding", true, null); |
| | | } |
| | | |
| | | /** |
| | | * AES解密 |
| | | * |
| | | * @param key |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public static byte[] aesDecrypt(byte[] content, String key) { |
| | | return decrypt(content, key.getBytes(), "AES/CBC/PKCS7Padding", true, null); |
| | | } |
| | | |
| | | /** |
| | | * 加密 |
| | | * |
| | | * @param content 待加密字符串 |
| | | * @param keyHex aesKye的hexStr |
| | | * @return |
| | | */ |
| | | public static String encrypt(String content, String keyHex) { |
| | | return HexUtil.encodeHexStr(encrypt(content.getBytes(), HexUtil.decodeHex(keyHex), CIPHER_INSTANCE, false, null)); |
| | | } |
| | | |
| | | /** |
| | | * 加密 |
| | | * |
| | | * @param content 待加密字符串 |
| | | * @param key 密钥 |
| | | * @return |
| | | */ |
| | | public static String encrypt(String content, byte[] key) { |
| | | return HexUtil.encodeHexStr(encrypt(content.getBytes(), key, CIPHER_INSTANCE, false, null)); |
| | | } |
| | | |
| | | /** |
| | | * 加密 |
| | | * |
| | | * @param content 待加密字符串 |
| | | * @param keyHex aesKye的hexStr |
| | | * @return |
| | | */ |
| | | public static byte[] encryptReturnByte(String content, String keyHex) { |
| | | return encrypt(content.getBytes(), HexUtil.decodeHex(keyHex), CIPHER_INSTANCE, false, null); |
| | | } |
| | | |
| | | /** |
| | | * 加密 |
| | | * |
| | | * @param content 待加密字符串 |
| | | * @param key 密钥 |
| | | * @return |
| | | */ |
| | | public static byte[] encryptReturnByte(String content, byte[] key) { |
| | | return encrypt(content.getBytes(), key, CIPHER_INSTANCE, false, null); |
| | | } |
| | | |
| | | /** |
| | | * 加密 |
| | | * |
| | | * @param content 待加密字符串 |
| | | * @param keyByte aesKye的hexStr |
| | | * @param cipherInstance AES算法填充方式 |
| | | * @param isIv 是否使用偏移量 ECB模式不可用 |
| | | * @param iv 偏移量 不传默认密钥 |
| | | * @return |
| | | */ |
| | | public static byte[] encrypt(byte[] content, byte[] keyByte, String cipherInstance, Boolean isIv, byte[] iv) { |
| | | try { |
| | | //KEY转换 |
| | | Key key = new SecretKeySpec(keyByte, AES_ALGORITHM); |
| | | //加密 |
| | | Cipher cipher = Cipher.getInstance(cipherInstance); |
| | | if (isIv != null && isIv) { |
| | | //偏移量 不传默认密钥 |
| | | if (iv == null) { |
| | | iv = keyByte; |
| | | } |
| | | IvParameterSpec ivps = new IvParameterSpec(iv); |
| | | cipher.init(Cipher.ENCRYPT_MODE, key, ivps); |
| | | } else { |
| | | cipher.init(Cipher.ENCRYPT_MODE, key); |
| | | } |
| | | byte[] result = cipher.doFinal(content); |
| | | return result; |
| | | } catch (NoSuchAlgorithmException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (InvalidKeyException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (NoSuchPaddingException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (BadPaddingException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (IllegalBlockSizeException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (InvalidAlgorithmParameterException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 解密 |
| | | * |
| | | * @param contentHex 待解密待字符串hexStr |
| | | * @param keyHex desKye的hexStr |
| | | * @return |
| | | */ |
| | | public static String decrypt(String contentHex, String keyHex) { |
| | | return new String(decrypt(HexUtil.decodeHex(contentHex), HexUtil.decodeHex(keyHex), CIPHER_INSTANCE, false, null)); |
| | | } |
| | | |
| | | /** |
| | | * 解密 |
| | | * |
| | | * @param contentHex 待解密待字符串hexStr |
| | | * @param key 密钥 |
| | | * @return |
| | | */ |
| | | public static String decrypt(String contentHex, byte[] key) { |
| | | return new String(decrypt(HexUtil.decodeHex(contentHex), key, CIPHER_INSTANCE, false, null)); |
| | | } |
| | | |
| | | /** |
| | | * 解密 |
| | | * |
| | | * @param content 待解密待内容 |
| | | * @param keyHex 密钥 |
| | | * @return |
| | | */ |
| | | public static String decrypt(byte[] content, String keyHex) { |
| | | return new String(decrypt(content, HexUtil.decodeHex(keyHex), CIPHER_INSTANCE, false, null)); |
| | | } |
| | | |
| | | /** |
| | | * 解密 |
| | | * |
| | | * @param content 待解密待内容 |
| | | * @param key 密钥 |
| | | * @return |
| | | */ |
| | | public static String decrypt(byte[] content, byte[] key) { |
| | | return new String(decrypt(content, key, CIPHER_INSTANCE, false, null)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 解密 |
| | | * |
| | | * @param contentByte 待解密待字符串hexStr |
| | | * @param contentByte 密钥 |
| | | * @param cipherInstance AES算法填充方式 |
| | | * @param isIv 是否使用偏移量 ECB模式不可用 |
| | | * @param iv 偏移量 不传默认密钥 |
| | | * @return |
| | | */ |
| | | public static byte[] decrypt(byte[] contentByte, byte[] keyByte, String cipherInstance, Boolean isIv, byte[] iv) { |
| | | try { |
| | | //KEY转换 |
| | | Key key = new SecretKeySpec(keyByte, AES_ALGORITHM); |
| | | //解密 |
| | | Cipher cipher = Cipher.getInstance(cipherInstance); |
| | | if (isIv != null && isIv) { |
| | | //偏移量 不传默认密钥 |
| | | if (iv == null) { |
| | | iv = keyByte; |
| | | } |
| | | IvParameterSpec ivps = new IvParameterSpec(iv); |
| | | cipher.init(Cipher.DECRYPT_MODE, key, ivps); |
| | | } else { |
| | | cipher.init(Cipher.DECRYPT_MODE, key); |
| | | } |
| | | byte[] result = cipher.doFinal(contentByte); |
| | | return result; |
| | | } catch (NoSuchAlgorithmException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (InvalidKeyException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (NoSuchPaddingException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (BadPaddingException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (IllegalBlockSizeException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } catch (InvalidAlgorithmParameterException e) { |
| | | LogUtils.e(e.getMessage(), e); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | |
| | | public static void main(String[] args) { |
| | | // jiemi(); |
| | | //jiami(); |
| | | } |
| | | |
| | | public static void jiami() { |
| | | String key = "1f6714fc-fb9b-4a"; |
| | | String content = "{\"id\":\"123\",\"objects\":[{\"sid\":\"0001011565879801020200010101\",\"type\":\"PWD\",\"local_id\":\"2\"}],\"time_stamp\":\"1603281282000\"}"; |
| | | byte[] res = aesEncrypt(content.getBytes(), key); |
| | | System.out.println(HexUtil.encodeHexStr(res)); |
| | | } |
| | | |
| | | // /** |
| | | // * |
| | | // * @param str |
| | | // * @param houseId |
| | | // * @return |
| | | // */ |
| | | // public static String jiemi(byte[] str, String houseId) { |
| | | // byte[] rs = aesDecrypt(str, HouseIdSecretUtil.getSecret(houseId)); |
| | | // String content = new String(rs); |
| | | // return content; |
| | | // } |
| | | |
| | | // public static void main(String[] args) { |
| | | // try { |
| | | // //第一步: 生成KEY |
| | | // //KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM); |
| | | // //keyGenerator.init(256); |
| | | // //第二步: 产生密钥 |
| | | // //SecretKey secretKey = keyGenerator.generateKey(); |
| | | // //第三步: 获取密钥 |
| | | // //byte[] keyBytes = secretKey.getEncoded(); |
| | | // //System.out.println(byteArrayToHexStr(keyBytes)); |
| | | // String src = "aaaaaaaaaVVVVaaaAAAA无"; |
| | | // String pwd = "41151AF257BFDB7859EEC62FB341EE95EE42E648FE24E1F8CE8DADE287CC1E5C"; |
| | | // String mw = encrypt(src,pwd); |
| | | // System.out.println("mw:"+mw); |
| | | // String jm = decrypt(mw,pwd); |
| | | // System.out.println("jm:"+jm); |
| | | // |
| | | // }catch (Exception e){ |
| | | // |
| | | // } |
| | | // |
| | | // } |
| | | } |
| | |
| | | while (isRun.get()) {
|
| | | if (client.isConnect()) {
|
| | | Log.d("=====", "==发送数据==");
|
| | |
|
| | | try {
|
| | | SocketRequest socketRequest = mMessageQueue.take();
|
| | | final String sendStr = new String(socketRequest.getData(), 0, socketRequest.getData().length);
|
| | | Log.d("=====", "==发送数据==:"+sendStr);
|
| | | final String action = socketRequest.getAction();
|
| | | try {
|
| | | client.sendMsg(socketRequest.getData());
|
New file |
| | |
| | | package com.hdl.sdk.socket;
|
| | |
|
| | | import com.hdl.sdk.socket.client.IClient;
|
| | |
|
| | | import java.net.DatagramSocket;
|
| | | import java.net.InetSocketAddress;
|
| | | import java.net.SocketException;
|
| | | import java.util.concurrent.ConcurrentHashMap;
|
| | |
|
| | | /**
|
| | | * Created by Tong on 2021/10/19.
|
| | | * 计划参考generic-pool、Commons Pool进行完善
|
| | | */
|
| | | public class SocketPool {
|
| | |
|
| | | private final ConcurrentHashMap<String, IClient> mPool;
|
| | | private final ConcurrentHashMap<String, DatagramSocket> mUdpClientPool;
|
| | |
|
| | | private SocketPool() {
|
| | | mPool = new ConcurrentHashMap<>();
|
| | | mUdpClientPool = new ConcurrentHashMap<>();
|
| | | }
|
| | |
|
| | |
|
| | | private static class SingletonInstance {
|
| | | private static final SocketPool INSTANCE = new SocketPool();
|
| | | }
|
| | |
|
| | | public static SocketPool getInstance() {
|
| | | return SingletonInstance.INSTANCE;
|
| | | }
|
| | |
|
| | | public void clear() {
|
| | | mPool.clear();
|
| | | mUdpClientPool.clear();
|
| | | }
|
| | |
|
| | | public synchronized DatagramSocket getUdpSocket(InetSocketAddress address) throws SocketException {
|
| | | DatagramSocket socket;
|
| | | final String key = address.toString();
|
| | | if (mUdpClientPool.containsKey(key)) {
|
| | | socket = mUdpClientPool.get(key);
|
| | | if (socket != null && !socket.isClosed()) {
|
| | | return socket;
|
| | | } else {
|
| | | socket = new DatagramSocket(address);
|
| | | }
|
| | | } else {
|
| | | socket = new DatagramSocket(address);
|
| | | }
|
| | | mUdpClientPool.put(address.toString(), socket);
|
| | | return socket;
|
| | | }
|
| | |
|
| | | }
|
| | |
| | | import com.hdl.sdk.common.utils.ThreadToolUtils;
|
| | | import com.hdl.sdk.socket.SocketBoot;
|
| | | import com.hdl.sdk.socket.SocketOptions;
|
| | | import com.hdl.sdk.socket.SocketPool;
|
| | | import com.hdl.sdk.socket.annotation.ConnectStatus;
|
| | | import com.hdl.sdk.socket.codec.IHandleMessage;
|
| | | import com.hdl.sdk.socket.listener.ConnectStatusListener;
|
| | |
| | | import java.net.DatagramPacket;
|
| | | import java.net.DatagramSocket;
|
| | | import java.net.InetAddress;
|
| | | import java.net.InetSocketAddress;
|
| | | import java.util.List;
|
| | | import java.util.concurrent.atomic.AtomicBoolean;
|
| | |
|
| | |
| | |
|
| | | @Override
|
| | | public void connect() throws Exception {
|
| | |
|
| | | try {
|
| | | mSocket = ClientPool.getInstance().getUdpSocket(ip, monitorPort);
|
| | | mSocket = SocketPool.getInstance().getUdpSocket(new InetSocketAddress(monitorPort));
|
| | |
|
| | | mSocket.setBroadcast(true);
|
| | | mSocket.setReuseAddress(true);
|
| | |
|
| | | isConnect.set(true);
|
| | | if (receivePacket == null) {
|
| | | receivePacket = new DatagramPacket(receiveByte, BUFFER);
|