diff --git a/common/src/main/java/com/pedro/common/Extensions.kt b/common/src/main/java/com/pedro/common/Extensions.kt index 53db4a494..f6a5c76ec 100644 --- a/common/src/main/java/com/pedro/common/Extensions.kt +++ b/common/src/main/java/com/pedro/common/Extensions.kt @@ -22,7 +22,10 @@ import android.os.Handler import android.os.Looper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import java.io.UnsupportedEncodingException import java.nio.ByteBuffer +import java.security.MessageDigest +import java.security.NoSuchAlgorithmException import java.util.concurrent.BlockingQueue import java.util.concurrent.ExecutorService @@ -82,4 +85,15 @@ fun ByteArray.bytesToHex(): String { fun ExecutorService.secureSubmit(code: () -> Unit) { try { submit { code() }.get() } catch (ignored: Exception) {} +} + +fun String.getMd5Hash(): String { + val md: MessageDigest + try { + md = MessageDigest.getInstance("MD5") + return md.digest(toByteArray()).bytesToHex() + } catch (ignore: NoSuchAlgorithmException) { + } catch (ignore: UnsupportedEncodingException) { + } + return "" } \ No newline at end of file diff --git a/common/src/test/java/com/pedro/common/ExtensionTest.kt b/common/src/test/java/com/pedro/common/ExtensionTest.kt index e55c5c5d1..3b7f84a64 100644 --- a/common/src/test/java/com/pedro/common/ExtensionTest.kt +++ b/common/src/test/java/com/pedro/common/ExtensionTest.kt @@ -52,4 +52,12 @@ class ExtensionTest { val expectedHex = numbersToHex.values.reduce { acc, s -> acc + s } assertEquals(expectedHex, testBytes.bytesToHex()) } + + @Test + fun `GIVEN String WHEN generate hash THEN return a MD5 hash String`() { + val fakeBuffer = "hello world" + val expectedResult = "5eb63bbbe01eeed093cb22bb8f5acdc3" + val md5Hash = fakeBuffer.getMd5Hash() + assertEquals(expectedResult, md5Hash) + } } \ No newline at end of file diff --git a/rtmp/src/main/java/com/pedro/rtmp/utils/AuthUtil.kt b/rtmp/src/main/java/com/pedro/rtmp/utils/AuthUtil.kt index d898181f8..0b2c8e3d3 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/utils/AuthUtil.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/utils/AuthUtil.kt @@ -16,10 +16,8 @@ package com.pedro.rtmp.utils -import com.pedro.common.bytesToHex -import java.io.UnsupportedEncodingException +import com.pedro.common.getMd5Hash import java.security.MessageDigest -import java.security.NoSuchAlgorithmException import java.util.Random import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi @@ -64,47 +62,17 @@ object AuthUtil { val queryPos = path.indexOf("?") if (queryPos >= 0) path = path.substring(0, queryPos) if (!path.contains("/")) path += "/_definst_" - val hash1 = getMd5Hash("$user:$realm:$password") - val hash2 = getMd5Hash("$method:/$path") - val hash3 = getMd5Hash("$hash1:$nonce:$ncHex:$cNonce:$qop:$hash2") + val hash1 = "$user:$realm:$password".getMd5Hash() + val hash2 = "$method:/$path".getMd5Hash() + val hash3 = "$hash1:$nonce:$ncHex:$cNonce:$qop:$hash2".getMd5Hash() return "?authmod=$authMod&user=$user&nonce=$nonce&cnonce=$cNonce&nc=$ncHex&response=$hash3" } - fun getSalt(description: String): String { - var salt = "" - val data = description.split("&").toTypedArray() - for (s in data) { - if (s.contains("salt=")) { - salt = s.substring(5) - break - } - } - return salt - } + fun getSalt(description: String): String = findDescriptionValue("salt=", description) - fun getChallenge(description: String): String { - var challenge = "" - val data = description.split("&").toTypedArray() - for (s in data) { - if (s.contains("challenge=")) { - challenge = s.substring(10) - break - } - } - return challenge - } + fun getChallenge(description: String): String = findDescriptionValue("challenge=", description) - fun getOpaque(description: String): String { - var opaque = "" - val data = description.split("&").toTypedArray() - for (s in data) { - if (s.contains("opaque=")) { - opaque = s.substring(7) - break - } - } - return opaque - } + fun getOpaque(description: String): String = findDescriptionValue("opaque=", description) @OptIn(ExperimentalEncodingApi::class) fun stringToMd5Base64(s: String): String { @@ -120,26 +88,15 @@ object AuthUtil { /** * Limelight auth utils */ - fun getNonce(description: String): String { - var nonce = "" + fun getNonce(description: String): String = findDescriptionValue("nonce=", description) + + private fun findDescriptionValue(value: String, description: String): String { val data = description.split("&").toTypedArray() for (s in data) { - if (s.contains("nonce=")) { - nonce = s.substring(6) - break + if (s.contains(value)) { + return s.substring(value.length) } } - return nonce - } - - fun getMd5Hash(buffer: String): String { - val md: MessageDigest - try { - md = MessageDigest.getInstance("MD5") - return md.digest(buffer.toByteArray()).bytesToHex() - } catch (ignore: NoSuchAlgorithmException) { - } catch (ignore: UnsupportedEncodingException) { - } return "" } } \ No newline at end of file diff --git a/rtsp/src/main/java/com/pedro/rtsp/rtsp/commands/CommandsManager.kt b/rtsp/src/main/java/com/pedro/rtsp/rtsp/commands/CommandsManager.kt index ca9c9b740..55969c60f 100644 --- a/rtsp/src/main/java/com/pedro/rtsp/rtsp/commands/CommandsManager.kt +++ b/rtsp/src/main/java/com/pedro/rtsp/rtsp/commands/CommandsManager.kt @@ -20,6 +20,7 @@ import android.util.Log import com.pedro.common.AudioCodec import com.pedro.common.TimeUtils import com.pedro.common.VideoCodec +import com.pedro.common.getMd5Hash import com.pedro.rtsp.rtsp.Protocol import com.pedro.rtsp.rtsp.commands.SdpBody.createAV1Body import com.pedro.rtsp.rtsp.commands.SdpBody.createAacBody @@ -27,7 +28,6 @@ import com.pedro.rtsp.rtsp.commands.SdpBody.createG711Body import com.pedro.rtsp.rtsp.commands.SdpBody.createH264Body import com.pedro.rtsp.rtsp.commands.SdpBody.createH265Body import com.pedro.rtsp.rtsp.commands.SdpBody.createOpusBody -import com.pedro.rtsp.utils.AuthUtil.getMd5Hash import com.pedro.rtsp.utils.RtpConstants import com.pedro.rtsp.utils.encodeToString import com.pedro.rtsp.utils.getData @@ -187,9 +187,9 @@ open class CommandsManager { Log.i(TAG, "using digest auth") val realm = matcher.group(1) val nonce = matcher.group(2) - val hash1 = getMd5Hash("$user:$realm:$password") - val hash2 = getMd5Hash("ANNOUNCE:rtsp://$host:$port$path") - val hash3 = getMd5Hash("$hash1:$nonce:$hash2") + val hash1 = "$user:$realm:$password".getMd5Hash() + val hash2 = "ANNOUNCE:rtsp://$host:$port$path".getMd5Hash() + val hash3 = "$hash1:$nonce:$hash2".getMd5Hash() "Digest username=\"$user\", realm=\"$realm\", nonce=\"$nonce\", uri=\"rtsp://$host:$port$path\", response=\"$hash3\"" //basic auth } else { diff --git a/rtsp/src/main/java/com/pedro/rtsp/utils/AuthUtil.kt b/rtsp/src/main/java/com/pedro/rtsp/utils/AuthUtil.kt deleted file mode 100644 index 0db762975..000000000 --- a/rtsp/src/main/java/com/pedro/rtsp/utils/AuthUtil.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2023 pedroSG94. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pedro.rtsp.utils - -import java.io.UnsupportedEncodingException -import java.security.MessageDigest -import java.security.NoSuchAlgorithmException - -object AuthUtil { - - @JvmStatic - fun getMd5Hash(buffer: String): String { - val md: MessageDigest - try { - md = MessageDigest.getInstance("MD5") - return bytesToHex(md.digest(buffer.toByteArray())) - } catch (ignore: NoSuchAlgorithmException) { - } catch (ignore: UnsupportedEncodingException) { - } - return "" - } - - private fun bytesToHex(raw: ByteArray): String { - return raw.joinToString("") { "%02x".format(it) } - } -} \ No newline at end of file diff --git a/rtsp/src/test/java/com/pedro/rtsp/utils/AuthUtilTest.kt b/rtsp/src/test/java/com/pedro/rtsp/utils/AuthUtilTest.kt deleted file mode 100644 index 645f88728..000000000 --- a/rtsp/src/test/java/com/pedro/rtsp/utils/AuthUtilTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2023 pedroSG94. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pedro.rtsp.utils - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Created by pedro on 14/4/22. - */ -class AuthUtilTest { - - @Test - fun `GIVEN String WHEN generate hash THEN return a MD5 hash String`() { - val fakeBuffer = "hello world" - val expectedResult = "5eb63bbbe01eeed093cb22bb8f5acdc3" - val md5Hash = AuthUtil.getMd5Hash(fakeBuffer) - assertEquals(expectedResult, md5Hash) - } -} \ No newline at end of file