mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-24 02:15:46 +03:00
QrCodeV2 WIP (al tests passing)
This commit is contained in:
parent
35b10daef1
commit
e00d3ef63d
7 changed files with 576 additions and 0 deletions
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.matrix.android.internal.crypto.verification.qrcode
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import org.amshove.kluent.shouldBeNull
|
||||
import org.amshove.kluent.shouldEqual
|
||||
import org.amshove.kluent.shouldEqualTo
|
||||
import org.amshove.kluent.shouldNotBeNull
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class QrCodeV2Test : InstrumentedTest {
|
||||
|
||||
private val qrCode1 = QrCodeDataV2.VerifyingAnotherUser(
|
||||
transactionId = "MaTransaction",
|
||||
userMasterCrossSigningPublicKey = "ktEwcUP6su1xh+GuE+CYkQ3H6W/DIl+ybHFdaEOrolU",
|
||||
otherUserMasterCrossSigningPublicKey = "TXluZKTZLvSRWOTPlOqLq534bA+/K4zLFKSu9cGLQaU",
|
||||
sharedSecret = "MTIzNDU2Nzg"
|
||||
)
|
||||
|
||||
private val value1 = "MATRIX\u0002\u0000\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
|
||||
|
||||
private val qrCode2 = QrCodeDataV2.SelfVerifyingMasterKeyTrusted(
|
||||
transactionId = "MaTransaction",
|
||||
userMasterCrossSigningPublicKey = "ktEwcUP6su1xh+GuE+CYkQ3H6W/DIl+ybHFdaEOrolU",
|
||||
otherDeviceKey = "TXluZKTZLvSRWOTPlOqLq534bA+/K4zLFKSu9cGLQaU",
|
||||
sharedSecret = "MTIzNDU2Nzg"
|
||||
)
|
||||
|
||||
private val value2 = "MATRIX\u0002\u0001\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
|
||||
|
||||
private val qrCode3 = QrCodeDataV2.SelfVerifyingMasterKeyNotTrusted(
|
||||
transactionId = "MaTransaction",
|
||||
deviceKey = "TXluZKTZLvSRWOTPlOqLq534bA+/K4zLFKSu9cGLQaU",
|
||||
userMasterCrossSigningPublicKey = "ktEwcUP6su1xh+GuE+CYkQ3H6W/DIl+ybHFdaEOrolU",
|
||||
sharedSecret = "MTIzNDU2Nzg"
|
||||
)
|
||||
|
||||
private val value3 = "MATRIX\u0002\u0002\u0000\u000DMaTransactionMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢U12345678"
|
||||
|
||||
private val sharedSecretByteArray = "12345678".toByteArray(Charsets.ISO_8859_1)
|
||||
|
||||
// 4d 79 6e 64 a4 d9 2e f4 91 58 e4 cf 94 ea 8b ab 9d f8 6c 0f bf 2b 8c cb 14 a4 ae f5 c1 8b 41 a5
|
||||
private val tlx_byteArray = ByteArray(32) {
|
||||
when (it) {
|
||||
0 -> 0x4D.toByte()
|
||||
1 -> 0x79.toByte()
|
||||
2 -> 0x6E.toByte()
|
||||
3 -> 0x64.toByte()
|
||||
4 -> 0xA4.toByte()
|
||||
5 -> 0xD9.toByte()
|
||||
6 -> 0x2E.toByte()
|
||||
7 -> 0xF4.toByte()
|
||||
8 -> 0x91.toByte()
|
||||
9 -> 0x58.toByte()
|
||||
10 -> 0xE4.toByte()
|
||||
11 -> 0xCF.toByte()
|
||||
12 -> 0x94.toByte()
|
||||
13 -> 0xEA.toByte()
|
||||
14 -> 0x8B.toByte()
|
||||
15 -> 0xAB.toByte()
|
||||
16 -> 0x9D.toByte()
|
||||
17 -> 0xF8.toByte()
|
||||
18 -> 0x6C.toByte()
|
||||
19 -> 0x0F.toByte()
|
||||
20 -> 0xBF.toByte()
|
||||
21 -> 0x2B.toByte()
|
||||
22 -> 0x8C.toByte()
|
||||
23 -> 0xCB.toByte()
|
||||
24 -> 0x14.toByte()
|
||||
25 -> 0xA4.toByte()
|
||||
26 -> 0xAE.toByte()
|
||||
27 -> 0xF5.toByte()
|
||||
28 -> 0xC1.toByte()
|
||||
29 -> 0x8B.toByte()
|
||||
30 -> 0x41.toByte()
|
||||
else -> 0xA5.toByte()
|
||||
}
|
||||
}
|
||||
|
||||
// 92 d1 30 71 43 fa b2 ed 71 87 e1 ae 13 e0 98 91 0d c7 e9 6f c3 22 5f b2 6c 71 5d 68 43 ab a2 55
|
||||
private val kte_byteArray = ByteArray(32) {
|
||||
when (it) {
|
||||
0 -> 0x92.toByte()
|
||||
1 -> 0xd1.toByte()
|
||||
2 -> 0x30.toByte()
|
||||
3 -> 0x71.toByte()
|
||||
4 -> 0x43.toByte()
|
||||
5 -> 0xfa.toByte()
|
||||
6 -> 0xb2.toByte()
|
||||
7 -> 0xed.toByte()
|
||||
8 -> 0x71.toByte()
|
||||
9 -> 0x87.toByte()
|
||||
10 -> 0xe1.toByte()
|
||||
11 -> 0xae.toByte()
|
||||
12 -> 0x13.toByte()
|
||||
13 -> 0xe0.toByte()
|
||||
14 -> 0x98.toByte()
|
||||
15 -> 0x91.toByte()
|
||||
16 -> 0x0d.toByte()
|
||||
17 -> 0xc7.toByte()
|
||||
18 -> 0xe9.toByte()
|
||||
19 -> 0x6f.toByte()
|
||||
20 -> 0xc3.toByte()
|
||||
21 -> 0x22.toByte()
|
||||
22 -> 0x5f.toByte()
|
||||
23 -> 0xb2.toByte()
|
||||
24 -> 0x6c.toByte()
|
||||
25 -> 0x71.toByte()
|
||||
26 -> 0x5d.toByte()
|
||||
27 -> 0x68.toByte()
|
||||
28 -> 0x43.toByte()
|
||||
29 -> 0xab.toByte()
|
||||
30 -> 0xa2.toByte()
|
||||
else -> 0x55.toByte()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncoding1() {
|
||||
qrCode1.toEncodedString() shouldEqual value1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncoding2() {
|
||||
qrCode2.toEncodedString() shouldEqual value2
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncoding3() {
|
||||
qrCode3.toEncodedString() shouldEqual value3
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSymmetry1() {
|
||||
qrCode1.toEncodedString().toQrCodeDataV2() shouldEqual qrCode1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSymmetry2() {
|
||||
qrCode2.toEncodedString().toQrCodeDataV2() shouldEqual qrCode2
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSymmetry3() {
|
||||
qrCode3.toEncodedString().toQrCodeDataV2() shouldEqual qrCode3
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCase1() {
|
||||
val url = qrCode1.toEncodedString()
|
||||
|
||||
val byteArray = url.toByteArray(Charsets.ISO_8859_1)
|
||||
checkHeader(byteArray)
|
||||
|
||||
// Mode
|
||||
byteArray[7] shouldEqualTo 0
|
||||
|
||||
checkSizeAndTransaction(byteArray)
|
||||
|
||||
compareArray(byteArray.copyOfRange(23, 23 + 32), kte_byteArray)
|
||||
compareArray(byteArray.copyOfRange(23 + 32, 23 + 64), tlx_byteArray)
|
||||
|
||||
compareArray(byteArray.copyOfRange(23 + 64, byteArray.size), sharedSecretByteArray)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCase2() {
|
||||
val url = qrCode2.toEncodedString()
|
||||
|
||||
val byteArray = url.toByteArray(Charsets.ISO_8859_1)
|
||||
checkHeader(byteArray)
|
||||
|
||||
// Mode
|
||||
byteArray[7] shouldEqualTo 1
|
||||
|
||||
checkSizeAndTransaction(byteArray)
|
||||
compareArray(byteArray.copyOfRange(23, 23 + 32), kte_byteArray)
|
||||
compareArray(byteArray.copyOfRange(23 + 32, 23 + 64), tlx_byteArray)
|
||||
|
||||
compareArray(byteArray.copyOfRange(23 + 64, byteArray.size), sharedSecretByteArray)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCase3() {
|
||||
val url = qrCode3.toEncodedString()
|
||||
|
||||
val byteArray = url.toByteArray(Charsets.ISO_8859_1)
|
||||
checkHeader(byteArray)
|
||||
|
||||
// Mode
|
||||
byteArray[7] shouldEqualTo 2
|
||||
|
||||
checkSizeAndTransaction(byteArray)
|
||||
compareArray(byteArray.copyOfRange(23, 23 + 32), tlx_byteArray)
|
||||
compareArray(byteArray.copyOfRange(23 + 32, 23 + 64), kte_byteArray)
|
||||
|
||||
compareArray(byteArray.copyOfRange(23 + 64, byteArray.size), sharedSecretByteArray)
|
||||
}
|
||||
|
||||
// Error cases
|
||||
@Test
|
||||
fun testErrorHeader() {
|
||||
value1.replace("MATRIX", "MOTRIX").toQrCodeDataV2().shouldBeNull()
|
||||
value1.replace("MATRIX", "MATRI").toQrCodeDataV2().shouldBeNull()
|
||||
value1.replace("MATRIX", "").toQrCodeDataV2().shouldBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorVersion() {
|
||||
value1.replace("MATRIX\u0002", "MATRIX\u0000").toQrCodeDataV2().shouldBeNull()
|
||||
value1.replace("MATRIX\u0002", "MATRIX\u0001").toQrCodeDataV2().shouldBeNull()
|
||||
value1.replace("MATRIX\u0002", "MATRIX\u0003").toQrCodeDataV2().shouldBeNull()
|
||||
value1.replace("MATRIX\u0002", "MATRIX").toQrCodeDataV2().shouldBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorSecretTooShort() {
|
||||
value1.replace("12345678", "1234567").toQrCodeDataV2().shouldBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorNoTransactionNoKeyNoSecret() {
|
||||
// But keep transaction length
|
||||
"MATRIX\u0002\u0000\u0000\u000D".toQrCodeDataV2().shouldBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorNoKeyNoSecret() {
|
||||
"MATRIX\u0002\u0000\u0000\u000DMaTransaction".toQrCodeDataV2().shouldBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorTransactionLengthTooShort() {
|
||||
// In this case, the secret will be longer, so this is not an error, but it will lead to keys mismatch
|
||||
value1.replace("\u000DMaTransaction", "\u000CMaTransaction").toQrCodeDataV2().shouldNotBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorTransactionLengthTooBig() {
|
||||
value1.replace("\u000DMaTransaction", "\u000EMaTransaction").toQrCodeDataV2().shouldBeNull()
|
||||
}
|
||||
|
||||
private fun compareArray(actual: ByteArray, expected: ByteArray) {
|
||||
actual.size shouldEqual expected.size
|
||||
|
||||
for (i in actual.indices) {
|
||||
actual[i] shouldEqualTo expected[i]
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkHeader(byteArray: ByteArray) {
|
||||
// MATRIX
|
||||
byteArray[0] shouldEqualTo 'M'.toByte()
|
||||
byteArray[1] shouldEqualTo 'A'.toByte()
|
||||
byteArray[2] shouldEqualTo 'T'.toByte()
|
||||
byteArray[3] shouldEqualTo 'R'.toByte()
|
||||
byteArray[4] shouldEqualTo 'I'.toByte()
|
||||
byteArray[5] shouldEqualTo 'X'.toByte()
|
||||
|
||||
// Version
|
||||
byteArray[6] shouldEqualTo 2
|
||||
}
|
||||
|
||||
private fun checkSizeAndTransaction(byteArray: ByteArray) {
|
||||
// Size
|
||||
byteArray[8] shouldEqualTo 0
|
||||
byteArray[9] shouldEqualTo 13
|
||||
|
||||
// Transaction
|
||||
byteArray.copyOfRange(10, 10 + "MaTransaction".length).toString(Charsets.ISO_8859_1) shouldEqual "MaTransaction"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.matrix.android.internal.crypto.verification.qrcode
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import org.amshove.kluent.shouldBe
|
||||
import org.amshove.kluent.shouldNotBeEqualTo
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class SharedSecretV2Test : InstrumentedTest {
|
||||
|
||||
@Test
|
||||
fun testSharedSecretLengthCase() {
|
||||
repeat(100) {
|
||||
generateSharedSecretV2().length shouldBe 11
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSharedDiffCase() {
|
||||
val sharedSecret1 = generateSharedSecretV2()
|
||||
val sharedSecret2 = generateSharedSecretV2()
|
||||
|
||||
sharedSecret1 shouldNotBeEqualTo sharedSecret2
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@ private const val ENCODING = "utf-8"
|
|||
* &other_device_key=WqSVLkBREDACTEDBsfszdvsdBEvefqsdcsfBvsfcsFb
|
||||
* </pre>
|
||||
*/
|
||||
// @Deprecated(message = "Use QrCodeDataV2")
|
||||
fun QrCodeData.toUrl(): String {
|
||||
return buildString {
|
||||
append(PermalinkFactory.createPermalink(userId))
|
||||
|
@ -72,6 +73,7 @@ fun QrCodeData.toUrl(): String {
|
|||
}
|
||||
}
|
||||
|
||||
// @Deprecated(message = "Use QrCodeDataV2")
|
||||
fun String.toQrCodeData(): QrCodeData? {
|
||||
if (!startsWith(PermalinkFactory.MATRIX_TO_URL_BASE)) {
|
||||
return null
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.matrix.android.internal.crypto.verification.qrcode
|
||||
|
||||
import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64NoPadding
|
||||
import im.vector.matrix.android.internal.crypto.crosssigning.toBase64NoPadding
|
||||
|
||||
// MATRIX
|
||||
private val prefix = "MATRIX".toByteArray(Charsets.ISO_8859_1)
|
||||
|
||||
fun QrCodeDataV2.toEncodedString(): String {
|
||||
var result = ByteArray(0)
|
||||
|
||||
// MATRIX
|
||||
for (i in prefix.indices) {
|
||||
result += prefix[i]
|
||||
}
|
||||
|
||||
// Version
|
||||
result += 2
|
||||
|
||||
// Mode
|
||||
result += when (this) {
|
||||
is QrCodeDataV2.VerifyingAnotherUser -> 0
|
||||
is QrCodeDataV2.SelfVerifyingMasterKeyTrusted -> 1
|
||||
is QrCodeDataV2.SelfVerifyingMasterKeyNotTrusted -> 2
|
||||
}.toByte()
|
||||
|
||||
// TransactionId length
|
||||
val length = transactionId.length
|
||||
result += ((length and 0xFF00) shr 8).toByte()
|
||||
result += length.toByte()
|
||||
|
||||
// TransactionId
|
||||
transactionId.forEach {
|
||||
result += it.toByte()
|
||||
}
|
||||
|
||||
// Keys
|
||||
firstKey.fromBase64NoPadding().forEach {
|
||||
result += it
|
||||
}
|
||||
secondKey.fromBase64NoPadding().forEach {
|
||||
result += it
|
||||
}
|
||||
|
||||
// Secret
|
||||
sharedSecret.fromBase64NoPadding().forEach {
|
||||
result += it
|
||||
}
|
||||
|
||||
return result.toString(Charsets.ISO_8859_1)
|
||||
}
|
||||
|
||||
fun String.toQrCodeDataV2(): QrCodeDataV2? {
|
||||
val byteArray = toByteArray(Charsets.ISO_8859_1)
|
||||
|
||||
// Size should be min 6 + 1 + 1 + 2 + ? + 32 + 32 + ? = 74 + transactionLength + secretLength
|
||||
|
||||
// Check header
|
||||
// MATRIX
|
||||
if (byteArray.size < 10) return null
|
||||
|
||||
for (i in prefix.indices) {
|
||||
if (byteArray[i] != prefix[i]) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
var cursor = prefix.size // 6
|
||||
|
||||
// Version
|
||||
if (byteArray[cursor] != 2.toByte()) {
|
||||
return null
|
||||
}
|
||||
cursor++
|
||||
|
||||
// Get mode
|
||||
val mode = byteArray[cursor].toInt()
|
||||
cursor++
|
||||
|
||||
// Get transaction length
|
||||
val transactionLength = (byteArray[cursor].toInt() shr 8) + byteArray[cursor + 1].toInt()
|
||||
|
||||
cursor++
|
||||
cursor++
|
||||
|
||||
val secretLength = byteArray.size - 74 - transactionLength
|
||||
|
||||
// ensure the secret length is 8 bytes min
|
||||
if (secretLength < 8) {
|
||||
return null
|
||||
}
|
||||
|
||||
val transactionId = byteArray.copyOfRange(cursor, cursor + transactionLength).toString(Charsets.ISO_8859_1)
|
||||
cursor += transactionLength
|
||||
val key1 = byteArray.copyOfRange(cursor, cursor + 32).toBase64NoPadding()
|
||||
cursor += 32
|
||||
val key2 = byteArray.copyOfRange(cursor, cursor + 32).toBase64NoPadding()
|
||||
cursor += 32
|
||||
val secret = byteArray.copyOfRange(cursor, byteArray.size).toBase64NoPadding()
|
||||
|
||||
return when (mode) {
|
||||
0 -> QrCodeDataV2.VerifyingAnotherUser(transactionId, key1, key2, secret)
|
||||
1 -> QrCodeDataV2.SelfVerifyingMasterKeyTrusted(transactionId, key1, key2, secret)
|
||||
2 -> QrCodeDataV2.SelfVerifyingMasterKeyNotTrusted(transactionId, key1, key2, secret)
|
||||
else -> null
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.verification.qrcode
|
|||
/**
|
||||
* Ref: https://github.com/uhoreg/matrix-doc/blob/qr_key_verification/proposals/1543-qr_code_key_verification.md#qr-code-format
|
||||
*/
|
||||
//@Deprecated(message = "Use QrCodeDataV2")
|
||||
data class QrCodeData(
|
||||
val userId: String,
|
||||
// Request Id. Can be an arbitrary value. In DM, it will be the event ID of the associated verification request event.
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.matrix.android.internal.crypto.verification.qrcode
|
||||
|
||||
/**
|
||||
* Ref: https://github.com/uhoreg/matrix-doc/blob/qr_key_verification/proposals/1543-qr_code_key_verification.md#qr-code-format
|
||||
*/
|
||||
sealed class QrCodeDataV2(
|
||||
/**
|
||||
* the event ID or transaction_id of the associated verification
|
||||
*/
|
||||
open val transactionId: String,
|
||||
/**
|
||||
* First key (32 bytes, in base64 no padding)
|
||||
*/
|
||||
val firstKey: String,
|
||||
/**
|
||||
* Second key (32 bytes, in base64 no padding)
|
||||
*/
|
||||
val secondKey: String,
|
||||
/**
|
||||
* a random shared secret (in base64 no padding)
|
||||
*/
|
||||
open val sharedSecret: String
|
||||
) {
|
||||
/**
|
||||
* verifying another user with cross-signing
|
||||
* QR code verification mode: 0x00
|
||||
*/
|
||||
data class VerifyingAnotherUser(
|
||||
override val transactionId: String,
|
||||
/**
|
||||
* the user's own master cross-signing public key
|
||||
*/
|
||||
val userMasterCrossSigningPublicKey: String,
|
||||
/**
|
||||
* what the device thinks the other user's master cross-signing key is
|
||||
*/
|
||||
val otherUserMasterCrossSigningPublicKey: String,
|
||||
override val sharedSecret: String
|
||||
) : QrCodeDataV2(
|
||||
transactionId,
|
||||
userMasterCrossSigningPublicKey,
|
||||
otherUserMasterCrossSigningPublicKey,
|
||||
sharedSecret)
|
||||
|
||||
/**
|
||||
* self-verifying in which the current device does trust the master key
|
||||
* QR code verification mode: 0x01
|
||||
*/
|
||||
data class SelfVerifyingMasterKeyTrusted(
|
||||
override val transactionId: String,
|
||||
/**
|
||||
* the user's own master cross-signing public key
|
||||
*/
|
||||
val userMasterCrossSigningPublicKey: String,
|
||||
/**
|
||||
* what the device thinks the other device's device key is
|
||||
*/
|
||||
val otherDeviceKey: String,
|
||||
override val sharedSecret: String
|
||||
) : QrCodeDataV2(
|
||||
transactionId,
|
||||
userMasterCrossSigningPublicKey,
|
||||
otherDeviceKey,
|
||||
sharedSecret)
|
||||
|
||||
/**
|
||||
* self-verifying in which the current device does not yet trust the master key
|
||||
* QR code verification mode: 0x02
|
||||
*/
|
||||
data class SelfVerifyingMasterKeyNotTrusted(
|
||||
override val transactionId: String,
|
||||
/**
|
||||
* the current device's device key
|
||||
*/
|
||||
val deviceKey: String,
|
||||
/**
|
||||
* what the device thinks the user's master cross-signing key is
|
||||
*/
|
||||
val userMasterCrossSigningPublicKey: String,
|
||||
override val sharedSecret: String
|
||||
) : QrCodeDataV2(
|
||||
transactionId,
|
||||
deviceKey,
|
||||
userMasterCrossSigningPublicKey,
|
||||
sharedSecret)
|
||||
}
|
|
@ -27,3 +27,12 @@ fun generateSharedSecret(): String {
|
|||
secureRandom.nextBytes(secretBytes)
|
||||
return secretBytes.toBase64NoPadding()
|
||||
}
|
||||
|
||||
fun generateSharedSecretV2(): String {
|
||||
val secureRandom = SecureRandom()
|
||||
|
||||
// 8 bytes long
|
||||
val secretBytes = ByteArray(8)
|
||||
secureRandom.nextBytes(secretBytes)
|
||||
return secretBytes.toBase64NoPadding()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue