From fc07abc89434d08119eb2aae9cf397cc1d8f2a74 Mon Sep 17 00:00:00 2001 From: norangebit Date: Wed, 24 Jun 2020 21:56:07 +0200 Subject: [PATCH] Fix toHexByteArray Add tests. --- build.gradle.kts | 5 +- .../it/unisannio/assd/tkn/Extensions.kt | 11 ++- .../assd/tkn/key/ReportAuthorizationKey.kt | 3 + .../assd/tkn/key/ReportVerificationKey.kt | 6 ++ .../assd/tkn/key/TemporaryContactKey.kt | 7 ++ .../assd/tkn/key/TemporaryContactNumber.kt | 2 +- .../unisannio/assd/tkn/report/SignedReport.kt | 2 +- .../kotlin/it/unisannio/assd/tkn/TestConst.kt | 20 +++++ .../tkn/key/ReportAuthorizationKeyTest.kt | 56 ++++++++++++++ .../assd/tkn/key/ReportVerificationKeyTest.kt | 74 +++++++++++++++++++ .../assd/tkn/key/TemporaryContactKeyTest.kt | 55 ++++++++++++++ .../unisannio/assd/tkn/report/ReportTest.kt | 41 ++++++++++ .../assd/tkn/report/SignedReportTest.kt | 26 +++++++ 13 files changed, 303 insertions(+), 5 deletions(-) create mode 100644 src/test/kotlin/it/unisannio/assd/tkn/TestConst.kt create mode 100644 src/test/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKeyTest.kt create mode 100644 src/test/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKeyTest.kt create mode 100644 src/test/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKeyTest.kt create mode 100644 src/test/kotlin/it/unisannio/assd/tkn/report/ReportTest.kt create mode 100644 src/test/kotlin/it/unisannio/assd/tkn/report/SignedReportTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 635caa8..6925f1b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,8 +15,11 @@ repositories { dependencies { implementation(kotlin("stdlib-jdk8")) - testCompile("junit", "junit", "4.12") implementation ("cafe.cryptography:ed25519-elisabeth:0.1.0") + + testCompile("junit", "junit", "4.12") + testImplementation ("org.amshove.kluent:kluent:1.61") + detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.9.1") } diff --git a/src/main/kotlin/it/unisannio/assd/tkn/Extensions.kt b/src/main/kotlin/it/unisannio/assd/tkn/Extensions.kt index f41ec75..727a5cf 100644 --- a/src/main/kotlin/it/unisannio/assd/tkn/Extensions.kt +++ b/src/main/kotlin/it/unisannio/assd/tkn/Extensions.kt @@ -1,6 +1,5 @@ package it.unisannio.assd.tkn -import java.math.BigInteger import java.nio.ByteBuffer import java.nio.ByteOrder @@ -21,7 +20,15 @@ fun ByteArray.toHexString(): String { return builder.toString() } -fun String.toHexByteArray(): ByteArray = BigInteger(this, 16).toByteArray() +fun String.toHexByteArray(): ByteArray { + val b = ByteArray(this.length / 2) + for (i in b.indices) { + val index = i * 2 + val v: Int = this.substring(index, index + 2).toInt(16) + b[i] = v.toByte() + } + return b +} fun ByteBuffer.read(n: Int): ByteArray { val bytes = ByteArray(n) diff --git a/src/main/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKey.kt b/src/main/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKey.kt index 0bad1d7..1fbfd6c 100644 --- a/src/main/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKey.kt +++ b/src/main/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKey.kt @@ -4,6 +4,7 @@ import cafe.cryptography.ed25519.Ed25519PrivateKey import cafe.cryptography.ed25519.Ed25519PublicKey import it.unisannio.assd.tkn.Const import it.unisannio.assd.tkn.toHexByteArray +import it.unisannio.assd.tkn.toHexString import java.security.MessageDigest import java.security.SecureRandom @@ -32,6 +33,8 @@ class ReportAuthorizationKey private constructor(private val key: Ed25519Private fun toByteArray(): ByteArray = key.toByteArray() + fun toHexString() = toByteArray().toHexString() + companion object { fun createFromByteArray(bytes: ByteArray): ReportAuthorizationKey = ReportAuthorizationKey( diff --git a/src/main/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKey.kt b/src/main/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKey.kt index 4614da9..b272488 100644 --- a/src/main/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKey.kt +++ b/src/main/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKey.kt @@ -3,6 +3,7 @@ package it.unisannio.assd.tkn.key import cafe.cryptography.ed25519.Ed25519PrivateKey import cafe.cryptography.ed25519.Ed25519PublicKey import cafe.cryptography.ed25519.Ed25519Signature +import it.unisannio.assd.tkn.toHexByteArray import it.unisannio.assd.tkn.toHexString class ReportVerificationKey private constructor(private val key: Ed25519PublicKey) { @@ -32,5 +33,10 @@ class ReportVerificationKey private constructor(private val key: Ed25519PublicKe ReportVerificationKey( Ed25519PublicKey.fromByteArray(bytes) ) + + fun createFromHexString(hexString: String): ReportVerificationKey = + ReportVerificationKey( + Ed25519PublicKey.fromByteArray(hexString.toHexByteArray()) + ) } } diff --git a/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKey.kt b/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKey.kt index d68adc3..6544e15 100644 --- a/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKey.kt +++ b/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKey.kt @@ -3,6 +3,7 @@ package it.unisannio.assd.tkn.key import it.unisannio.assd.tkn.Const import it.unisannio.assd.tkn.report.Memo import it.unisannio.assd.tkn.report.Report +import it.unisannio.assd.tkn.toHexByteArray import it.unisannio.assd.tkn.toHexString import it.unisannio.assd.tkn.toLeByteArray import java.security.MessageDigest @@ -71,5 +72,11 @@ class TemporaryContactKey private constructor( bytes, index ) + + fun createFromHexString(hexString: String, index: Short): TemporaryContactKey = + TemporaryContactKey( + hexString.toHexByteArray(), + index + ) } } diff --git a/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactNumber.kt b/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactNumber.kt index 3436730..52f968d 100644 --- a/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactNumber.kt +++ b/src/main/kotlin/it/unisannio/assd/tkn/key/TemporaryContactNumber.kt @@ -2,7 +2,7 @@ package it.unisannio.assd.tkn.key import it.unisannio.assd.tkn.toHexString import java.nio.ByteBuffer -import java.util.* +import java.util.UUID class TemporaryContactNumber( private val number: ByteArray, diff --git a/src/main/kotlin/it/unisannio/assd/tkn/report/SignedReport.kt b/src/main/kotlin/it/unisannio/assd/tkn/report/SignedReport.kt index ee6a0df..ab3a57f 100644 --- a/src/main/kotlin/it/unisannio/assd/tkn/report/SignedReport.kt +++ b/src/main/kotlin/it/unisannio/assd/tkn/report/SignedReport.kt @@ -8,7 +8,7 @@ import java.nio.ByteOrder class SignedReport private constructor( val report: Report, - private val sign: ByteArray + val sign: ByteArray ) { fun verify(): Boolean = report.getVerificationKey() .verify(report.toByteArray(), sign) diff --git a/src/test/kotlin/it/unisannio/assd/tkn/TestConst.kt b/src/test/kotlin/it/unisannio/assd/tkn/TestConst.kt new file mode 100644 index 0000000..06b497a --- /dev/null +++ b/src/test/kotlin/it/unisannio/assd/tkn/TestConst.kt @@ -0,0 +1,20 @@ +package it.unisannio.assd.tkn + +/** + * These data were derived from the TCN project test vector. + * For more information see https://github.com/TCNCoalition/TCN#reporting. + */ +object TestConst { + const val PRIVATE_KEY_STRING_HEX = "577cfdae21fee71579211ab02c418ee0948bacab613cf69d0a4a5ae5a1557dbb" + const val PUBLIC_KEY_STRING_HEX = "fd8deb9d91a13e144ca5b0ce14e289532e040fe0bf922c6e3dadb1e4e2333c78" + const val TCK_0 = "aeca765f744b47faf1fc297bfcaf802fc6c9a8f2e2c9f2d65a7bdc7f42359164" + const val TCK_1 = "df535b90ac99bec8be3a8add45ce77897b1e7cb1906b5cff1097d3cb142fd9d0" + const val TCN_1 = "f4350a4a33e30f2f568898fbe4c4cf34" + const val TCN_2 = "135eeaa6482b8852fea3544edf6eabf0" + const val TCN_3 = "d713ce68cf4127bcebde6874c4991e4b" + const val MESSAGE = "test message" + const val REPORT_MESSAGE = "fd8deb9d91a13e144ca5b0ce14e289532e040fe0bf922c6e3dadb1e4e2333c78df535b90ac99" + + "bec8be3a8add45ce77897b1e7cb1906b5cff1097d3cb142fd9d002000a00000c73796d70746f6d2064617461" + const val REPORT_SIGN = "31078ec5367b67a8c793b740626d81ba904789363137b5a313419c0f50b180d8226ecc984bf073ff" + + "89cbd9c88fea06bda1f0f368b0e7e88bbe68f15574482904" +} diff --git a/src/test/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKeyTest.kt b/src/test/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKeyTest.kt new file mode 100644 index 0000000..cd072f1 --- /dev/null +++ b/src/test/kotlin/it/unisannio/assd/tkn/key/ReportAuthorizationKeyTest.kt @@ -0,0 +1,56 @@ +package it.unisannio.assd.tkn.key + +import cafe.cryptography.ed25519.Ed25519PrivateKey +import it.unisannio.assd.tkn.TestConst.MESSAGE +import it.unisannio.assd.tkn.TestConst.PRIVATE_KEY_STRING_HEX +import it.unisannio.assd.tkn.TestConst.PUBLIC_KEY_STRING_HEX +import it.unisannio.assd.tkn.TestConst.TCK_0 +import it.unisannio.assd.tkn.toHexByteArray +import org.amshove.kluent.`should be equal to` +import org.junit.Test + +class ReportAuthorizationKeyTest { + @Test + fun createFromByteArray() { + val keyBytes = PRIVATE_KEY_STRING_HEX.toHexByteArray() + + val rak = ReportAuthorizationKey.createFromByteArray(keyBytes) + + rak.toHexString() `should be equal to` PRIVATE_KEY_STRING_HEX + } + + @Test + fun createFromHexString() { + val rak = ReportAuthorizationKey.createFromHexString(PRIVATE_KEY_STRING_HEX) + + rak.toHexString() `should be equal to` PRIVATE_KEY_STRING_HEX + } + + @Test + fun deriveVerificationKey() { + val rak = ReportAuthorizationKey.createFromHexString(PRIVATE_KEY_STRING_HEX) + + rak.deriveVerificationKey() + .toHexString() `should be equal to` PUBLIC_KEY_STRING_HEX + } + + @Test + fun deriveTck0() { + val rak = ReportAuthorizationKey.createFromHexString(PRIVATE_KEY_STRING_HEX) + + rak.baseTemporaryContactKey() + .toHexString() `should be equal to` TCK_0 + } + + @Test + fun sign() { + val rak = ReportAuthorizationKey.createFromHexString(PRIVATE_KEY_STRING_HEX) + val rvk = rak.deriveVerificationKey() + val privateKey = Ed25519PrivateKey.fromByteArray(PRIVATE_KEY_STRING_HEX.toHexByteArray()) + val publicKey = privateKey.derivePublic() + + val message = MESSAGE.toByteArray() + + rak.sign(message, rvk) `should be equal to` privateKey.expand().sign(message, publicKey).toByteArray() + } +} diff --git a/src/test/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKeyTest.kt b/src/test/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKeyTest.kt new file mode 100644 index 0000000..8b0c0d3 --- /dev/null +++ b/src/test/kotlin/it/unisannio/assd/tkn/key/ReportVerificationKeyTest.kt @@ -0,0 +1,74 @@ +package it.unisannio.assd.tkn.key + +import it.unisannio.assd.tkn.TestConst +import it.unisannio.assd.tkn.toHexByteArray +import org.amshove.kluent.`should be equal to` +import org.junit.Test + +class ReportVerificationKeyTest { + @Test + fun createFromByteArray() { + val rvk = ReportVerificationKey + .createFromByteArray(TestConst.PUBLIC_KEY_STRING_HEX.toHexByteArray()) + + println(rvk.toHexString()) + + rvk.toHexString() `should be equal to` TestConst.PUBLIC_KEY_STRING_HEX + } + + @Test + fun createFromAuthorizationKey() { + val rak = ReportAuthorizationKey + .createFromHexString(TestConst.PRIVATE_KEY_STRING_HEX) + + ReportVerificationKey + .createFromAuthorizationKey(rak) + .toHexString() `should be equal to` TestConst.PUBLIC_KEY_STRING_HEX + } + + @Test + fun createFromHexString() { + val rvk = ReportVerificationKey + .createFromHexString(TestConst.PUBLIC_KEY_STRING_HEX) + + rvk.toHexString() `should be equal to` TestConst.PUBLIC_KEY_STRING_HEX + } + + @Test + fun verify() { + val rvk = ReportVerificationKey + .createFromHexString(TestConst.PUBLIC_KEY_STRING_HEX) + + rvk.verify( + TestConst.REPORT_MESSAGE.toHexByteArray(), + TestConst.REPORT_SIGN.toHexByteArray() + ) `should be equal to` true + } + + @Test + fun verifyFalse() { + val rvk = ReportVerificationKey + .createFromHexString(TestConst.PUBLIC_KEY_STRING_HEX) + + rvk.verify( + "not original message".toByteArray(), + TestConst.REPORT_SIGN.toHexByteArray() + ) `should be equal to` false + } + + @Test + fun contactNumbersBetween() { + val rak = ReportAuthorizationKey + .createFromHexString(TestConst.PRIVATE_KEY_STRING_HEX) + val rvk = ReportVerificationKey + .createFromHexString(TestConst.PUBLIC_KEY_STRING_HEX) + + rvk.contactNumbersBetween( + rak.baseTemporaryContactKey(), + 1, + 4 + ).map { + it.toHexString() + } `should be equal to` listOf(TestConst.TCN_1, TestConst.TCN_2, TestConst.TCN_3) + } +} diff --git a/src/test/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKeyTest.kt b/src/test/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKeyTest.kt new file mode 100644 index 0000000..825889e --- /dev/null +++ b/src/test/kotlin/it/unisannio/assd/tkn/key/TemporaryContactKeyTest.kt @@ -0,0 +1,55 @@ +package it.unisannio.assd.tkn.key + +import it.unisannio.assd.tkn.TestConst +import it.unisannio.assd.tkn.toHexByteArray +import org.amshove.kluent.`should be equal to` +import org.junit.Test + +class TemporaryContactKeyTest { + @Test + fun createFromByteArray() { + val tck0 = TemporaryContactKey + .createFromByteArray(TestConst.TCK_0.toHexByteArray(), 0) + + tck0.toHexString() `should be equal to` TestConst.TCK_0 + } + + @Test + fun createFromHexString() { + val tck0 = TemporaryContactKey + .createFromHexString(TestConst.TCK_0, 0) + + tck0.toHexString() `should be equal to` TestConst.TCK_0 + } + + @Test + fun nextTemporaryKey() { + val tck0 = TemporaryContactKey + .createFromHexString(TestConst.TCK_0, 0) + val rvk = ReportVerificationKey + .createFromHexString(TestConst.PUBLIC_KEY_STRING_HEX) + + tck0.nextTemporaryContactKey(rvk) + .toHexString() `should be equal to` TestConst.TCK_1 + } + + @Test + fun derivateTemporaryContactNumber() { + val tck1 = TemporaryContactKey + .createFromHexString(TestConst.TCK_1, 1) + + tck1.deriveTemporaryContactNumber() + .toHexString() `should be equal to` TestConst.TCN_1 + } + + @Test + fun generateReport() { + val tck1 = TemporaryContactKey + .createFromHexString(TestConst.TCK_1, 1) + val rvk = ReportVerificationKey + .createFromHexString(TestConst.PUBLIC_KEY_STRING_HEX) + + tck1.generateReport(rvk, 10, "symptom data") + .toHexString() `should be equal to` TestConst.REPORT_MESSAGE + } +} diff --git a/src/test/kotlin/it/unisannio/assd/tkn/report/ReportTest.kt b/src/test/kotlin/it/unisannio/assd/tkn/report/ReportTest.kt new file mode 100644 index 0000000..ca33948 --- /dev/null +++ b/src/test/kotlin/it/unisannio/assd/tkn/report/ReportTest.kt @@ -0,0 +1,41 @@ +package it.unisannio.assd.tkn.report + +import it.unisannio.assd.tkn.TestConst +import it.unisannio.assd.tkn.key.ReportAuthorizationKey +import it.unisannio.assd.tkn.toHexByteArray +import it.unisannio.assd.tkn.toHexString +import org.amshove.kluent.`should be equal to` +import org.junit.Test + +class ReportTest { + @Test + fun readReportFromByteArray() { + val report = Report.readReportFromByteArray( + TestConst.REPORT_MESSAGE.toHexByteArray() + ) + + report.toHexString() `should be equal to` TestConst.REPORT_MESSAGE + } + + @Test + fun signWith() { + val report = Report.readReportFromByteArray( + TestConst.REPORT_MESSAGE.toHexByteArray() + ) + val rak = ReportAuthorizationKey + .createFromHexString(TestConst.PRIVATE_KEY_STRING_HEX) + + report.signWith(rak).sign + .toHexString() `should be equal to` TestConst.REPORT_SIGN + } + + @Test + fun getVerificationKey() { + val report = Report.readReportFromByteArray( + TestConst.REPORT_MESSAGE.toHexByteArray() + ) + + report.getVerificationKey() + .toHexString() `should be equal to` TestConst.PUBLIC_KEY_STRING_HEX + } +} diff --git a/src/test/kotlin/it/unisannio/assd/tkn/report/SignedReportTest.kt b/src/test/kotlin/it/unisannio/assd/tkn/report/SignedReportTest.kt new file mode 100644 index 0000000..4e2f180 --- /dev/null +++ b/src/test/kotlin/it/unisannio/assd/tkn/report/SignedReportTest.kt @@ -0,0 +1,26 @@ +package it.unisannio.assd.tkn.report + +import it.unisannio.assd.tkn.TestConst +import it.unisannio.assd.tkn.toHexByteArray +import org.amshove.kluent.`should be equal to` +import org.junit.Test + +class SignedReportTest { + @Test + fun readFromByteArray() { + val report = TestConst.REPORT_MESSAGE + TestConst.REPORT_SIGN + + SignedReport.readFromByteArray( + report.toHexByteArray() + ).toHexString() `should be equal to` report + } + + @Test + fun verify() { + val report = TestConst.REPORT_MESSAGE + TestConst.REPORT_SIGN + + SignedReport.readFromByteArray( + report.toHexByteArray() + ).verify() `should be equal to` true + } +}