From 538f440b3d2992b2951dd03a57c565ee64c1f32a Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Fri, 21 Oct 2022 11:18:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A`HttpServer`?= =?UTF-8?q?=E8=AF=B7=E6=B1=82/=E5=BA=94=E7=AD=94=E6=8A=A5=E6=96=87?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C`=E5=9B=BD=E5=AF=86SM4`=E5=AF=B9=E7=A7=B0?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E4=BC=A0=E8=BE=93=20=E3=80=90=E9=85=8D?= =?UTF-8?q?=E5=A5=97`SmsF`=E5=BE=AE=E4=BF=A1=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E3=80=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 3 + .../sms/forwarder/fragment/ClientFragment.kt | 74 ++++++++++---- .../sms/forwarder/fragment/ServerFragment.kt | 28 ++++++ .../fragment/client/BatteryQueryFragment.kt | 49 ++++++--- .../fragment/client/CallQueryFragment.kt | 49 ++++++--- .../fragment/client/CloneFragment.kt | 97 +++++++++++++----- .../fragment/client/ContactQueryFragment.kt | 49 ++++++--- .../fragment/client/SmsQueryFragment.kt | 49 ++++++--- .../fragment/client/SmsSendFragment.kt | 49 ++++++--- .../fragment/client/WolSendFragment.kt | 49 ++++++--- .../server/component/AppExceptionResolver.kt | 26 +++-- .../server/component/AppMessageConverter.kt | 35 +++++-- .../server/component/LoginInterceptor.kt | 1 + .../idormy/sms/forwarder/utils/Constants.kt | 2 + .../sms/forwarder/utils/HttpServerUtils.kt | 8 ++ .../idormy/sms/forwarder/utils/SM4Crypt.kt | 62 ++++++++++++ app/src/main/res/layout/fragment_client.xml | 55 +++++++---- app/src/main/res/layout/fragment_server.xml | 99 +++++++++++++++---- app/src/main/res/values-en/strings.xml | 8 +- app/src/main/res/values/strings.xml | 8 +- app/src/main/res/values/styles_widget.xml | 6 +- 21 files changed, 621 insertions(+), 185 deletions(-) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/utils/SM4Crypt.kt diff --git a/app/build.gradle b/app/build.gradle index 33409a05..d5f28629 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -264,6 +264,9 @@ dependencies { //HTTP服务器:https://github.com/yanzhenjie/AndServer implementation 'cn.ppps.andserver:api:2.1.11' kapt 'cn.ppps.andserver:processor:2.1.11' + + //国密算法SM4 的JAVA实现(基于BC实现) + api "org.bouncycastle:bcprov-jdk15on:1.69" } //自动添加X-Library依赖 apply from: 'x-library.gradle' diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt index 490f90fd..b3795c5f 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt @@ -36,6 +36,8 @@ import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xutil.XUtil +import com.xuexiang.xutil.data.ConvertTools + @Suppress("PrivatePropertyName", "PropertyName") @Page(name = "主动控制·客户端") @@ -123,6 +125,10 @@ class ClientFragment : BaseFragment(), View.OnClickListe safetyMeasuresId = R.id.rb_safety_measures_rsa binding!!.tvSignKey.text = getString(R.string.public_key) } + 3 -> { + safetyMeasuresId = R.id.rb_safety_measures_sm4 + binding!!.tvSignKey.text = getString(R.string.sm4_key) + } else -> { binding!!.layoutSignKey.visibility = View.GONE } @@ -130,19 +136,23 @@ class ClientFragment : BaseFragment(), View.OnClickListe binding!!.rgSafetyMeasures.check(safetyMeasuresId) binding!!.rgSafetyMeasures.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int -> var safetyMeasures = 0 - binding!!.layoutSignKey.visibility = View.GONE + binding!!.layoutSignKey.visibility = View.VISIBLE when (checkedId) { R.id.rb_safety_measures_sign -> { safetyMeasures = 1 binding!!.tvSignKey.text = getString(R.string.sign_key) - binding!!.layoutSignKey.visibility = View.VISIBLE } R.id.rb_safety_measures_rsa -> { safetyMeasures = 2 binding!!.tvSignKey.text = getString(R.string.public_key) - binding!!.layoutSignKey.visibility = View.VISIBLE } - else -> {} + R.id.rb_safety_measures_sm4 -> { + safetyMeasures = 3 + binding!!.tvSignKey.text = getString(R.string.sm4_key) + } + else -> { + binding!!.layoutSignKey.visibility = View.GONE + } } HttpServerUtils.clientSafetyMeasures = safetyMeasures } @@ -195,6 +205,10 @@ class ClientFragment : BaseFragment(), View.OnClickListe safetyMeasuresId = R.id.rb_safety_measures_rsa binding!!.tvSignKey.text = getString(R.string.public_key) } + "3" -> { + safetyMeasuresId = R.id.rb_safety_measures_sm4 + binding!!.tvSignKey.text = getString(R.string.sm4_key) + } else -> { binding!!.tvSignKey.visibility = View.GONE binding!!.etSignKey.visibility = View.GONE @@ -254,8 +268,8 @@ class ClientFragment : BaseFragment(), View.OnClickListe msgMap["timestamp"] = timestamp val clientSignKey = HttpServerUtils.clientSignKey.toString() - if ((HttpServerUtils.clientSafetyMeasures == 1 || HttpServerUtils.clientSafetyMeasures == 2) && TextUtils.isEmpty(clientSignKey)) { - if (needToast) XToastUtils.error("请输入签名密钥或RSA公钥") + if (HttpServerUtils.clientSafetyMeasures != 0 && TextUtils.isEmpty(clientSignKey)) { + if (needToast) XToastUtils.error("请输入签名密钥/RSA公钥/SM4密钥") return } @@ -273,20 +287,37 @@ class ClientFragment : BaseFragment(), View.OnClickListe .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s .cacheMode(CacheMode.NO_CACHE).timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - if (needToast) XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + try { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + if (needToast) XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + if (needToast) XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } if (needToast) mCountDownHelper?.start() @@ -304,6 +335,11 @@ class ClientFragment : BaseFragment(), View.OnClickListe val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse = Gson().fromJson(json, object : TypeToken>() {}.type) if (resp.code == 200) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt index 42f9da85..0fc0ca4c 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt @@ -27,6 +27,7 @@ import com.xuexiang.xui.widget.button.SmoothCheckBox import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xui.widget.picker.XSeekBar import com.xuexiang.xutil.app.ServiceUtils +import com.xuexiang.xutil.data.ConvertTools import com.xuexiang.xutil.net.NetworkUtils import com.xuexiang.xutil.system.ClipboardUtils import java.io.File @@ -92,6 +93,10 @@ class ServerFragment : BaseFragment(), View.OnClickListe binding!!.layoutPrivateKey.visibility = View.VISIBLE binding!!.layoutPublicKey.visibility = View.VISIBLE } + 3 -> { + safetyMeasuresId = R.id.rb_safety_measures_sm4 + binding!!.layoutSm4Key.visibility = View.VISIBLE + } else -> {} } binding!!.rgSafetyMeasures.check(safetyMeasuresId) @@ -101,6 +106,7 @@ class ServerFragment : BaseFragment(), View.OnClickListe binding!!.layoutTimeTolerance.visibility = View.GONE binding!!.layoutPrivateKey.visibility = View.GONE binding!!.layoutPublicKey.visibility = View.GONE + binding!!.layoutSm4Key.visibility = View.GONE when (checkedId) { R.id.rb_safety_measures_sign -> { safetyMeasures = 1 @@ -112,11 +118,26 @@ class ServerFragment : BaseFragment(), View.OnClickListe binding!!.layoutPrivateKey.visibility = View.VISIBLE binding!!.layoutPublicKey.visibility = View.VISIBLE } + R.id.rb_safety_measures_sm4 -> { + safetyMeasures = 3 + binding!!.layoutSm4Key.visibility = View.VISIBLE + } else -> {} } HttpServerUtils.safetyMeasures = safetyMeasures } + //SM4密钥 + binding!!.btnSm4Key.setOnClickListener(this) + binding!!.etSm4Key.setText(HttpServerUtils.serverSm4Key) + binding!!.etSm4Key.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} + override fun afterTextChanged(s: Editable) { + HttpServerUtils.serverSm4Key = binding!!.etSm4Key.text.toString().trim() + } + }) + //RSA公私钥 binding!!.btnCopyPublicKey.setOnClickListener(this) binding!!.btnGenerateKey.setOnClickListener(this) @@ -221,6 +242,13 @@ class ServerFragment : BaseFragment(), View.OnClickListe } refreshButtonText() } + R.id.btn_sm4_key -> { + val key = ConvertTools.bytes2HexString(SM4Crypt.createSM4Key()) + println("SM4密钥:$key") + ClipboardUtils.copyText(key) + binding!!.etSm4Key.setText(key) + XToastUtils.info(getString(R.string.sign_key_tips)) + } R.id.btn_generate_key -> { val generator = KeyPairGenerator.getInstance("RSA") //密钥生成器 generator.initialize(2048) diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/BatteryQueryFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/BatteryQueryFragment.kt index 0045a796..ca816e79 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/BatteryQueryFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/BatteryQueryFragment.kt @@ -20,6 +20,7 @@ import com.xuexiang.xrouter.utils.TextUtils import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.grouplist.XUIGroupListView +import com.xuexiang.xutil.data.ConvertTools @Suppress("PropertyName") @Page(name = "远程查电量") @@ -67,20 +68,37 @@ class BatteryQueryFragment : BaseFragment() .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + try { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } postRequest.execute(object : SimpleCallBack() { @@ -96,6 +114,11 @@ class BatteryQueryFragment : BaseFragment() val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse = Gson().fromJson(json, object : TypeToken>() {}.type) if (resp.code == 200) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CallQueryFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CallQueryFragment.kt index 4ce778c7..f6b0f789 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CallQueryFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CallQueryFragment.kt @@ -35,6 +35,7 @@ import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xui.utils.SnackbarUtils import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.searchview.MaterialSearchView +import com.xuexiang.xutil.data.ConvertTools import com.xuexiang.xutil.data.DateUtils import com.xuexiang.xutil.system.ClipboardUtils import me.samlss.broccoli.Broccoli @@ -216,20 +217,37 @@ class CallQueryFragment : BaseFragment() { .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + try { + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } postRequest.execute(object : SimpleCallBack() { @@ -245,6 +263,11 @@ class CallQueryFragment : BaseFragment() { val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse?> = Gson().fromJson(json, object : TypeToken?>>() {}.type) if (resp.code == 200) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt index 120c8959..7fd0430d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt @@ -31,6 +31,7 @@ import com.xuexiang.xui.utils.CountDownButtonHelper import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xutil.app.AppUtils +import com.xuexiang.xutil.data.ConvertTools import com.xuexiang.xutil.file.FileIOUtils import com.xuexiang.xutil.file.FileUtils import java.io.File @@ -255,20 +256,37 @@ class CloneFragment : BaseFragment(), View.OnClickL .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + try { + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } postRequest.execute(object : SimpleCallBack() { @@ -285,6 +303,11 @@ class CloneFragment : BaseFragment(), View.OnClickL val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse = Gson().fromJson(json, object : TypeToken>() {}.type) if (resp.code == 200) { @@ -336,20 +359,37 @@ class CloneFragment : BaseFragment(), View.OnClickL .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + try { + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } postRequest.execute(object : SimpleCallBack() { @@ -366,6 +406,11 @@ class CloneFragment : BaseFragment(), View.OnClickL val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } //替换Date字段为当前时间 diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt index d821b66a..75b6aa18 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt @@ -36,6 +36,7 @@ import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xui.utils.SnackbarUtils import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.searchview.MaterialSearchView +import com.xuexiang.xutil.data.ConvertTools import com.xuexiang.xutil.system.ClipboardUtils import me.samlss.broccoli.Broccoli @@ -199,20 +200,37 @@ class ContactQueryFragment : BaseFragment() .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + try { + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } postRequest.execute(object : SimpleCallBack() { @@ -228,6 +246,11 @@ class ContactQueryFragment : BaseFragment() val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse?> = Gson().fromJson(json, object : TypeToken?>>() {}.type) if (resp.code == 200) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt index 53d36a65..ea995bea 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt @@ -37,6 +37,7 @@ import com.xuexiang.xui.utils.SnackbarUtils import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.searchview.MaterialSearchView import com.xuexiang.xui.widget.searchview.MaterialSearchView.SearchViewListener +import com.xuexiang.xutil.data.ConvertTools import com.xuexiang.xutil.data.DateUtils import me.samlss.broccoli.Broccoli @@ -206,20 +207,37 @@ class SmsQueryFragment : BaseFragment() { .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + try { + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } postRequest.execute(object : SimpleCallBack() { @@ -235,6 +253,11 @@ class SmsQueryFragment : BaseFragment() { val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse?> = Gson().fromJson(json, object : TypeToken?>>() {}.type) if (resp.code == 200) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsSendFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsSendFragment.kt index 1545fb05..a0bc8b01 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsSendFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsSendFragment.kt @@ -23,6 +23,7 @@ import com.xuexiang.xrouter.utils.TextUtils import com.xuexiang.xui.utils.CountDownButtonHelper import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xui.widget.actionbar.TitleBar +import com.xuexiang.xutil.data.ConvertTools @Suppress("PropertyName") @Page(name = "远程发短信") @@ -121,20 +122,37 @@ class SmsSendFragment : BaseFragment(), View.OnCl .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + try { + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } mCountDownHelper?.start() @@ -152,6 +170,11 @@ class SmsSendFragment : BaseFragment(), View.OnCl val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse = Gson().fromJson(json, object : TypeToken>() {}.type) if (resp.code == 200) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/WolSendFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/WolSendFragment.kt index 10567b9d..97afb608 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/WolSendFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/WolSendFragment.kt @@ -23,6 +23,7 @@ import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog +import com.xuexiang.xutil.data.ConvertTools @Suppress("PropertyName") @Page(name = "远程WOL") @@ -151,20 +152,37 @@ class WolSendFragment : BaseFragment(), View.OnCl .cacheMode(CacheMode.NO_CACHE) .timeStamp(true) - if (HttpServerUtils.clientSafetyMeasures == 2) { - val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) - try { - requestMsg = Base64.encode(requestMsg.toByteArray()) - requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) - Log.i(TAG, "requestMsg: $requestMsg") - } catch (e: Exception) { - XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) - e.printStackTrace() - return + when (HttpServerUtils.clientSafetyMeasures) { + 2 -> { + val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) + try { + requestMsg = Base64.encode(requestMsg.toByteArray()) + requestMsg = RSACrypt.encryptByPublicKey(requestMsg, publicKey) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + 3 -> { + try { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + //requestMsg = Base64.encode(requestMsg.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(requestMsg.toByteArray(), sm4Key) + requestMsg = ConvertTools.bytes2HexString(encryptCBC) + Log.i(TAG, "requestMsg: $requestMsg") + } catch (e: Exception) { + XToastUtils.error(ResUtils.getString(R.string.request_failed) + e.message) + e.printStackTrace() + return + } + postRequest.upString(requestMsg) + } + else -> { + postRequest.upJson(requestMsg) } - postRequest.upString(requestMsg) - } else { - postRequest.upJson(requestMsg) } mCountDownHelper?.start() @@ -182,6 +200,11 @@ class WolSendFragment : BaseFragment(), View.OnCl val publicKey = RSACrypt.getPublicKey(HttpServerUtils.clientSignKey.toString()) json = RSACrypt.decryptByPublicKey(json, publicKey) json = String(Base64.decode(json)) + } else if (HttpServerUtils.clientSafetyMeasures == 3) { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + json = String(decryptCBC) } val resp: BaseResponse = Gson().fromJson(json, object : TypeToken>() {}.type) if (resp.code == 200) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/server/component/AppExceptionResolver.kt b/app/src/main/java/com/idormy/sms/forwarder/server/component/AppExceptionResolver.kt index f163a0a5..63a9b93c 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/server/component/AppExceptionResolver.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/server/component/AppExceptionResolver.kt @@ -4,6 +4,8 @@ import android.util.Log import com.idormy.sms.forwarder.utils.Base64 import com.idormy.sms.forwarder.utils.HttpServerUtils import com.idormy.sms.forwarder.utils.RSACrypt +import com.idormy.sms.forwarder.utils.SM4Crypt +import com.xuexiang.xutil.data.ConvertTools import com.yanzhenjie.andserver.annotation.Resolver import com.yanzhenjie.andserver.error.HttpException import com.yanzhenjie.andserver.framework.ExceptionResolver @@ -13,6 +15,7 @@ import com.yanzhenjie.andserver.http.HttpRequest import com.yanzhenjie.andserver.http.HttpResponse import com.yanzhenjie.andserver.http.StatusCode +@Suppress("PrivatePropertyName") @Resolver class AppExceptionResolver : ExceptionResolver { @@ -31,13 +34,22 @@ class AppExceptionResolver : ExceptionResolver { //返回统一结构报文 var resp = HttpServerUtils.response(e.message.toString()) Log.d(TAG, "resp: $resp") - if (HttpServerUtils.safetyMeasures != 2) { - response.setBody(JsonBody(resp)) - } else { - val privateKey = RSACrypt.getPrivateKey(HttpServerUtils.serverPrivateKey.toString()) - resp = Base64.encode(resp.toByteArray()) - resp = RSACrypt.encryptByPrivateKey(resp, privateKey) - response.setBody(StringBody(resp)) + when (HttpServerUtils.safetyMeasures) { + 2 -> { + val privateKey = RSACrypt.getPrivateKey(HttpServerUtils.serverPrivateKey.toString()) + resp = Base64.encode(resp.toByteArray()) + resp = RSACrypt.encryptByPrivateKey(resp, privateKey) + response.setBody(StringBody(resp)) + } + 3 -> { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.serverSm4Key.toString()) + //response = Base64.encode(response.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(resp.toByteArray(), sm4Key) + response.setBody(StringBody(ConvertTools.bytes2HexString(encryptCBC))) + } + else -> { + response.setBody(JsonBody(resp)) + } } } diff --git a/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt b/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt index 43f8f247..36c222c4 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt @@ -6,7 +6,9 @@ import com.idormy.sms.forwarder.server.model.BaseRequest import com.idormy.sms.forwarder.utils.Base64 import com.idormy.sms.forwarder.utils.HttpServerUtils import com.idormy.sms.forwarder.utils.RSACrypt +import com.idormy.sms.forwarder.utils.SM4Crypt import com.xuexiang.xrouter.utils.TextUtils +import com.xuexiang.xutil.data.ConvertTools import com.yanzhenjie.andserver.annotation.Converter import com.yanzhenjie.andserver.error.HttpException import com.yanzhenjie.andserver.framework.MessageConverter @@ -32,14 +34,21 @@ class AppMessageConverter : MessageConverter { var response = HttpServerUtils.response(output) Log.d(TAG, "response: $response") - if (HttpServerUtils.safetyMeasures != 2) { - return JsonBody(response) + return when (HttpServerUtils.safetyMeasures) { + 2 -> { + val privateKey = RSACrypt.getPrivateKey(HttpServerUtils.serverPrivateKey.toString()) + response = Base64.encode(response.toByteArray()) + response = RSACrypt.encryptByPrivateKey(response, privateKey) + StringBody(response) + } + 3 -> { + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.serverSm4Key.toString()) + //response = Base64.encode(response.toByteArray()) + val encryptCBC = SM4Crypt.encrypt(response.toByteArray(), sm4Key) + StringBody(ConvertTools.bytes2HexString(encryptCBC)) + } + else -> JsonBody(response) } - - val privateKey = RSACrypt.getPrivateKey(HttpServerUtils.serverPrivateKey.toString()) - response = Base64.encode(response.toByteArray()) - response = RSACrypt.encryptByPrivateKey(response, privateKey) - return StringBody(response) } @Throws(IOException::class) @@ -60,6 +69,18 @@ class AppMessageConverter : MessageConverter { json = RSACrypt.decryptByPrivateKey(json, privateKey) json = String(Base64.decode(json)) Log.d(TAG, "Json: $json") + } else if (HttpServerUtils.safetyMeasures == 3) { + if (TextUtils.isEmpty(HttpServerUtils.serverSm4Key)) { + Log.e(TAG, "SM4解密失败: SM4密钥为空") + throw HttpException(500, "服务端未配置SM4密钥") + } + + val sm4Key = ConvertTools.hexStringToByteArray(HttpServerUtils.clientSignKey.toString()) + val encryptCBC = ConvertTools.hexStringToByteArray(json) + val decryptCBC = SM4Crypt.decrypt(encryptCBC, sm4Key) + //json = String(Base64.decode(decryptCBC.toString())) + json = String(decryptCBC) + Log.d(TAG, "Json: $json") } //修改接口数据中的null、“”为默认值 diff --git a/app/src/main/java/com/idormy/sms/forwarder/server/component/LoginInterceptor.kt b/app/src/main/java/com/idormy/sms/forwarder/server/component/LoginInterceptor.kt index 1a74bfa8..321b5cc0 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/server/component/LoginInterceptor.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/server/component/LoginInterceptor.kt @@ -9,6 +9,7 @@ import com.yanzhenjie.andserver.http.HttpRequest import com.yanzhenjie.andserver.http.HttpResponse //@Interceptor +@Suppress("unused") class LoginInterceptor : HandlerInterceptor { override fun onIntercept( request: HttpRequest, diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt index 5bfb308c..3b57f20a 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt @@ -325,6 +325,7 @@ const val SP_ENABLE_SERVER_AUTORUN = "enable_server_autorun" const val SP_SERVER_SAFETY_MEASURES = "server_safety_measures" const val SP_SERVER_SIGN_KEY = "server_sign_key" const val SP_SERVER_TIME_TOLERANCE = "server_time_tolerance" +const val SP_SERVER_SM4_KEY = "server_sm4_key" const val SP_SERVER_PUBLIC_KEY = "server_public_key" const val SP_SERVER_PRIVATE_KEY = "server_private_key" const val SP_SERVER_WEB_PATH = "server_web_path" @@ -341,6 +342,7 @@ const val SP_SERVER_HISTORY = "server_history" const val SP_SERVER_CONFIG = "server_config" const val SP_CLIENT_SAFETY_MEASURES = "client_safety_measures" const val SP_CLIENT_SIGN_KEY = "client_sign_key" + var CLIENT_FRAGMENT_LIST = listOf( PageInfo( getString(R.string.api_clone), diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt index ee0f16a7..3a53d73b 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt @@ -40,6 +40,14 @@ class HttpServerUtils private constructor() { MMKVUtils.put(SP_SERVER_SAFETY_MEASURES, safetyMeasures) } + //服务端SM4密钥 + @JvmStatic + var serverSm4Key: String? + get() = MMKVUtils.getString(SP_SERVER_SM4_KEY, "") + set(serverSm4Key) { + MMKVUtils.put(SP_SERVER_SM4_KEY, serverSm4Key) + } + //服务端RSA公钥 @JvmStatic var serverPublicKey: String? diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SM4Crypt.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/SM4Crypt.kt new file mode 100644 index 00000000..a6e16e8e --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SM4Crypt.kt @@ -0,0 +1,62 @@ +package com.idormy.sms.forwarder.utils + +import org.bouncycastle.jce.provider.BouncyCastleProvider +import java.security.SecureRandom +import javax.crypto.Cipher +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec + +/** + * SM4分组密码算法是我国自主设计的分组对称密码算法 + */ +@Suppress("unused", "MemberVisibilityCanBePrivate") +object SM4Crypt { + + const val SM4_CBC_NOPADDING = "SM4/CBC/NoPadding" + const val SM4_CBC_PKCS5 = "SM4/CBC/PKCS5Padding" + const val SM4_CBC_PKCS7 = "SM4/CBC/PKCS7Padding" + const val SM4_ECB_NOPADDING = "SM4/ECB/NoPadding" + const val SM4_ECB_PKCS5 = "SM4/ECB/PKCS5Padding" + const val SM4_ECB_PKCS7 = "SM4/ECB/PKCS7Padding" + private val BC_PROVIDER = BouncyCastleProvider() + private val SM4_CBC_IV = byteArrayOf(3, 5, 6, 9, 6, 9, 5, 9, 3, 5, 6, 9, 6, 9, 5, 9) + + /** + * 获取随机密钥 + */ + fun createSM4Key(): ByteArray { + val seed = ByteArray(16) + val random = SecureRandom() + random.nextBytes(seed) + return seed + } + + @JvmOverloads + fun encrypt(source: ByteArray, key: ByteArray, mode: String = SM4_CBC_PKCS7, iv: ByteArray? = SM4_CBC_IV): ByteArray { + return doSM4(true, source, key, mode, iv) + } + + @JvmOverloads + fun decrypt(source: ByteArray, key: ByteArray, mode: String = SM4_CBC_PKCS7, iv: ByteArray? = SM4_CBC_IV): ByteArray { + return doSM4(false, source, key, mode, iv) + } + + private fun doSM4(forEncryption: Boolean, source: ByteArray, key: ByteArray, mode: String, iv: ByteArray?): ByteArray { + return try { + val cryptMode = if (forEncryption) 1 else 2 + val sm4Key = SecretKeySpec(key, "SM4") + val cipher = Cipher.getInstance(mode, BC_PROVIDER) + if (iv == null) { + cipher.init(cryptMode, sm4Key) + } else { + val ivParameterSpec = IvParameterSpec(iv) + cipher.init(cryptMode, sm4Key, ivParameterSpec) + } + cipher.doFinal(source) + } catch (var9: Exception) { + var9.printStackTrace() + ByteArray(0) + } + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_client.xml b/app/src/main/res/layout/fragment_client.xml index cfbb8fb0..c919d976 100644 --- a/app/src/main/res/layout/fragment_client.xml +++ b/app/src/main/res/layout/fragment_client.xml @@ -67,42 +67,57 @@ style="@style/settingBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> + android:orientation="vertical" + android:paddingEnd="10dp" + tools:ignore="RtlSymmetry"> - + android:gravity="center_vertical" + android:orientation="horizontal"> + + + + + + + android:text="@string/safety_measures_none" /> + style="@style/rg_rb_style" + android:text="@string/safety_measures_sign" /> + style="@style/rg_rb_style" + android:text="@string/safety_measures_rsa" /> + + diff --git a/app/src/main/res/layout/fragment_server.xml b/app/src/main/res/layout/fragment_server.xml index 4f2102aa..e259227e 100644 --- a/app/src/main/res/layout/fragment_server.xml +++ b/app/src/main/res/layout/fragment_server.xml @@ -137,42 +137,57 @@ style="@style/settingBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> + android:orientation="vertical" + android:paddingEnd="10dp" + tools:ignore="RtlSymmetry"> - + android:gravity="center_vertical" + android:orientation="horizontal"> + + + + + + + android:text="@string/safety_measures_none" /> + style="@style/rg_rb_style" + android:text="@string/safety_measures_sign" /> + style="@style/rg_rb_style" + android:text="@string/safety_measures_rsa" /> + + @@ -365,6 +380,47 @@ + + + + + + + + + + + android:layout_height="wrap_content" + tools:ignore="TooManyViews"> Input keywords to fuzzy match SMS content Pure numbers match numbers / non-numbers match names Input keyword to fuzzy match mobile phone number - Fill two items according to the config of server, the signature key is optional + Fill these items according to the config of server Server Url E.g: http://127.0.0.1:5000 Features List @@ -925,9 +925,11 @@ 0=disabled, scan when battery change Day Safety Measures + The client and server must be the same. It is strongly recommended to enable encryption when accessing the public network. None Sign - Encrypt + RSA Encrypt + SM4 Encrypt See Github Wiki, download to Download directory Time Tolerance Minimize time tolerance to avoid request replay attacks @@ -937,4 +939,6 @@ Public Key Public key is used on the client: client request message public key encryption, server private key decryption Copy + SM4 Key + Client or server interaction messages are all encrypted and decrypted using SM4 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 62c70227..03e594df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -877,7 +877,7 @@ 输入关键字模糊匹配短信内容 纯数字匹配号码/非数字匹配姓名 输入关键字模糊匹配手机号码 - 按照主动控制·服务端的配置填写以下两项,签名密钥可选 + 按照主动控制·服务端的配置填写以下项目 服务地址 例如:http://127.0.0.1:5000 功能列表 @@ -926,9 +926,11 @@ 0=禁用,触发机制:每次电量变化时扫描 安全措施 + 客户端与服务端必须一致,强烈建议公网访问时启用加密 不需要 校验签名 - 加密传输 + RSA加密 + SM4加密 参见 Github Wiki,下载到 Download 目录 客户端与服务端时间容差 尽量缩短时间容差,避免请求重放攻击 @@ -938,4 +940,6 @@ RSA公钥 RSA公钥用在客户端:客户端请求报文公钥加密,服务端私钥解密 复制公钥 + SM4密钥 + 客户端/服务端交互采用SM4加解密 diff --git a/app/src/main/res/values/styles_widget.xml b/app/src/main/res/values/styles_widget.xml index d95ab90b..fd1b7ab0 100644 --- a/app/src/main/res/values/styles_widget.xml +++ b/app/src/main/res/values/styles_widget.xml @@ -179,7 +179,7 @@ true 0dp 0dp - 13sp + 12sp \ No newline at end of file