Updated on 2026-08-14

This commit is contained in:
Tangem 2019-11-18 11:35:11 +03:00
parent 4c64438643
commit 66a56a7344
16 changed files with 383 additions and 172 deletions

View file

@ -1,4 +1,5 @@
apply plugin: "kotlin"
apply plugin: 'org.jetbrains.dokka'
group = 'com.github.TangemCash'
version '0.1.0'
@ -9,6 +10,8 @@ dependencies {
implementation "com.madgag.spongycastle:core:1.56.0.0"
implementation "com.madgag.spongycastle:prov:1.56.0.0"
implementation 'net.i2p.crypto:eddsa:0.3.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
testImplementation "com.google.truth:truth:1.0"
}
sourceCompatibility = "8"
@ -16,15 +19,19 @@ targetCompatibility = "8"
buildscript {
ext.kotlin_version = '1.3.50'
ext.dokka_version = '0.10.0'
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
}
}
repositories {
mavenCentral()
jcenter()
}
compileKotlin {
kotlinOptions {
@ -36,3 +43,7 @@ compileTestKotlin {
jvmTarget = "1.8"
}
}
task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
outputFormat = 'markdown'
}

View file

@ -4,8 +4,8 @@ import com.tangem.CardEnvironment
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.extentions.calculateSha256
import com.tangem.common.extentions.hexToBytes
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.TlvMapper
import com.tangem.common.tlv.TlvTag

View file

@ -3,7 +3,7 @@ package com.tangem.commands
import com.tangem.CardEnvironment
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.extentions.toInt
import com.tangem.common.extensions.toInt
import com.tangem.common.tlv.TlvTag
/**

View file

@ -4,7 +4,7 @@ import com.tangem.CardEnvironment
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.extentions.calculateSha256
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.TlvMapper
import com.tangem.common.tlv.TlvTag

View file

@ -4,8 +4,8 @@ import com.tangem.CardEnvironment
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.Instruction
import com.tangem.common.apdu.ResponseApdu
import com.tangem.common.extentions.calculateSha256
import com.tangem.common.extentions.hexToBytes
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.TlvMapper
import com.tangem.common.tlv.TlvTag

View file

@ -1,4 +1,4 @@
package com.tangem.common.extentions
package com.tangem.common.extensions
import java.nio.ByteBuffer
import java.security.MessageDigest
@ -28,9 +28,9 @@ fun ByteArray.toInt(): Int {
}
fun ByteArray.toDate(): Date {
val year = ((this[0] and 0xFF.toByte()).toInt() shl 8) or (this[1] and 0xFF.toByte()).toInt()
val month = this[2] - 1
val day = this[3].toInt()
val year = copyOfRange(0, 2).toInt()
val month = if (this.size > 2) this[2] - 1 else 0
val day = if (this.size > 3) this[3].toInt() else 0
val cd = Calendar.getInstance()
cd.set(year, month, day, 0, 0, 0)
return cd.time

View file

@ -1,4 +1,4 @@
package com.tangem.common.extentions
package com.tangem.common.extensions
import java.nio.charset.Charset
import java.security.MessageDigest
@ -13,10 +13,8 @@ fun String.calculateSha256(): ByteArray {
}
fun String.hexToBytes(): ByteArray {
val bytes = ByteArray(this.length / 2)
for (i in bytes.indices) {
bytes[i] = Integer.parseInt(this.substring(2 * i, 2 * i + 2),
16).toByte()
return ByteArray(this.length / 2)
{ i ->
Integer.parseInt(this.substring(2 * i, 2 * i + 2), 16).toByte()
}
return bytes
}

View file

@ -1,10 +1,10 @@
package com.tangem.common.tlv
import com.tangem.commands.*
import com.tangem.common.extentions.toDate
import com.tangem.common.extentions.toHexString
import com.tangem.common.extentions.toInt
import com.tangem.common.extentions.toUtf8
import com.tangem.common.extensions.toDate
import com.tangem.common.extensions.toHexString
import com.tangem.common.extensions.toInt
import com.tangem.common.extensions.toUtf8
import java.util.*

View file

@ -40,7 +40,7 @@ object CryptoUtils {
fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray,
curve: EllipticCurve = EllipticCurve.Secp256k1): Boolean {
return when (curve) {
EllipticCurve.Secp256k1 -> Sepc256k1.verify(publicKey, message, signature)
EllipticCurve.Secp256k1 -> Secp256k1.verify(publicKey, message, signature)
EllipticCurve.Ed25519 -> Ed25519.verify(publicKey, message, signature)
}
}
@ -58,7 +58,7 @@ object CryptoUtils {
curve: EllipticCurve = EllipticCurve.Secp256k1
): ByteArray {
return when (curve) {
EllipticCurve.Secp256k1 -> Sepc256k1.generatePublicKey(privateKeyArray)
EllipticCurve.Secp256k1 -> Secp256k1.generatePublicKey(privateKeyArray)
EllipticCurve.Ed25519 -> Ed25519.generatePublicKey(privateKeyArray)
}
}
@ -74,8 +74,8 @@ object CryptoUtils {
*/
fun ByteArray.sign(privateKeyArray: ByteArray, curve: EllipticCurve = EllipticCurve.Secp256k1): ByteArray {
return when (curve) {
EllipticCurve.Secp256k1 -> signSecp256k1(this, privateKeyArray)
EllipticCurve.Ed25519 -> signEd25519(this, privateKeyArray)
EllipticCurve.Secp256k1 -> Secp256k1.sign(this, privateKeyArray)
EllipticCurve.Ed25519 -> Ed25519.sign(this, privateKeyArray)
}
}

View file

@ -1,6 +1,6 @@
package com.tangem.crypto
import com.tangem.common.extentions.calculateSha512
import com.tangem.common.extensions.calculateSha512
import net.i2p.crypto.eddsa.EdDSAEngine
import net.i2p.crypto.eddsa.EdDSAPrivateKey
import net.i2p.crypto.eddsa.EdDSAPublicKey
@ -10,36 +10,46 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
import java.security.MessageDigest
import java.security.PublicKey
internal fun verifyEd25519(publicKey: ByteArray, message: ByteArray, signature: ByteArray): Boolean {
val messageSha512 = message.calculateSha512()
val loadedPublicKey = loadPublicKey(publicKey)
val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
val signatureInstance = EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm))
signatureInstance.initVerify(loadedPublicKey)
object Ed25519 {
signatureInstance.update(messageSha512)
internal fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray): Boolean {
val messageSha512 = message.calculateSha512()
val loadedPublicKey = loadPublicKey(publicKey)
val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
val signatureInstance = EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm))
signatureInstance.initVerify(loadedPublicKey)
return signatureInstance.verify(signature)
}
signatureInstance.update(messageSha512)
private fun loadPublicKey(publicKeyArray: ByteArray): PublicKey {
val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
val pubKey = EdDSAPublicKeySpec(publicKeyArray, spec)
return EdDSAPublicKey(pubKey)
}
return signatureInstance.verify(signature)
}
internal fun signEd25519(data: ByteArray, privateKeyArray: ByteArray): ByteArray {
private fun loadPublicKey(publicKeyArray: ByteArray): PublicKey {
val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
val pubKey = EdDSAPublicKeySpec(publicKeyArray, spec)
return EdDSAPublicKey(pubKey)
}
val dataSha512 = data.calculateSha512()
val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
val signatureInstance = EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm))
internal fun sign(data: ByteArray, privateKeyArray: ByteArray): ByteArray {
val privateKeySpec = EdDSAPrivateKeySpec(privateKeyArray, spec)
val privateKey = EdDSAPrivateKey(privateKeySpec)
val dataSha512 = data.calculateSha512()
val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
val signatureInstance = EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm))
signatureInstance.initSign(privateKey)
signatureInstance.update(dataSha512)
val privateKeySpec = EdDSAPrivateKeySpec(privateKeyArray, spec)
val privateKey = EdDSAPrivateKey(privateKeySpec)
return signatureInstance.sign()
signatureInstance.initSign(privateKey)
signatureInstance.update(dataSha512)
return signatureInstance.sign()
}
internal fun generatePublicKey(privateKeyArray: ByteArray): ByteArray {
val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519)
val privateKeySpec = EdDSAPrivateKeySpec(privateKeyArray, spec)
val publicKeySpec = EdDSAPublicKeySpec(privateKeySpec.a, spec)
val publicKey = EdDSAPublicKey(publicKeySpec)
return publicKey.abyte
}
}

View file

@ -0,0 +1,118 @@
package com.tangem.crypto
import com.tangem.common.extensions.toHexString
import org.spongycastle.asn1.ASN1EncodableVector
import org.spongycastle.asn1.ASN1Integer
import org.spongycastle.asn1.DERSequence
import org.spongycastle.jce.ECNamedCurveTable
import org.spongycastle.jce.spec.ECPrivateKeySpec
import org.spongycastle.jce.spec.ECPublicKeySpec
import java.math.BigInteger
import java.security.KeyFactory
import java.security.PublicKey
import java.security.Signature
object Secp256k1 {
internal fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray): Boolean {
val signatureInstance = Signature.getInstance("SHA256withECDSA")
val loadedPublicKey = loadPublicKey(publicKey)
signatureInstance.initVerify(loadedPublicKey)
signatureInstance.update(message)
val v = ASN1EncodableVector()
val size = signature.size / 2
v.add(calculateR(signature, size))
v.add(calculateS(signature, size))
val sigDer = DERSequence(v).encoded
return signatureInstance.verify(sigDer)
}
private fun loadPublicKey(publicKeyArray: ByteArray): PublicKey {
val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
val factory = KeyFactory.getInstance("EC", "SC")
val p1 = spec.curve.decodePoint(publicKeyArray)
val keySpec = ECPublicKeySpec(p1, spec)
return factory.generatePublic(keySpec)
}
private fun calculateR(signature: ByteArray, size: Int): ASN1Integer =
ASN1Integer(BigInteger(1, signature.copyOfRange(0, size)))
private fun calculateS(signature: ByteArray, size: Int): ASN1Integer =
ASN1Integer(BigInteger(1, signature.copyOfRange(size, size * 2)))
internal fun sign(data: ByteArray, privateKeyArray: ByteArray): ByteArray {
val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
val factory = KeyFactory.getInstance("EC", "SC")
val keySpecP = ECPrivateKeySpec(BigInteger(1, privateKeyArray), spec)
val signature = Signature.getInstance("SHA256withECDSA")
val privateKey = factory.generatePrivate(keySpecP)
signature.initSign(privateKey)
signature.update(data)
val enc = signature.sign()
checkSignatureForErrors(enc)
val res = toByte64(enc)
if (!verify(generatePublicKey(privateKeyArray), data, res)) {
throw Exception("Signature self verify failed - ,enc:" + enc.toHexString() + ",res:" + res.toHexString())
}
return res
}
private fun checkSignatureForErrors(enc: ByteArray) {
if (enc[0].toInt() != 0x30) throw Exception("bad encoding 1")
if (enc[1].toInt() and 0x80 != 0) throw Exception("unsupported length encoding 1")
if (enc[2].toInt() != 0x02) throw Exception("bad encoding 2")
if (enc[3].toInt() and 0x80 != 0) throw Exception("unsupported length encoding 2")
var rLength = enc[3].toInt()
if (enc[4 + rLength].toInt() != 0x02) throw Exception("bad encoding 3")
if (enc[5 + rLength].toInt() and 0x80 != 0)
throw Exception("unsupported length encoding 3")
}
private fun toByte64(enc: ByteArray): ByteArray {
var rLength = enc[3].toInt()
var sLength = enc[5 + rLength].toInt()
val sPos = 6 + rLength
val res = ByteArray(64)
if (rLength <= 32) {
System.arraycopy(enc, 4, res, 32 - rLength, rLength)
rLength = 32
} else if (rLength == 33 && enc[4].toInt() == 0) {
rLength--
System.arraycopy(enc, 5, res, 0, rLength)
} else {
throw Exception("unsupported r-length - r-length:" + rLength.toString() + ",s-length:" + sLength.toString() + ",enc:" + enc.toHexString())
}
if (sLength <= 32) {
System.arraycopy(enc, sPos, res, rLength + 32 - sLength, sLength)
sLength = 32
} else if (sLength == 33 && enc[sPos].toInt() == 0) {
System.arraycopy(enc, sPos + 1, res, rLength, sLength - 1)
} else {
throw Exception("unsupported s-length - r-length:" + rLength.toString() + ",s-length:" + sLength.toString() + ",enc:" + enc.toHexString())
}
return res
}
internal fun generatePublicKey(privateKeyArray: ByteArray): ByteArray {
val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
return spec.g.multiply(BigInteger(1, privateKeyArray)).getEncoded(false)
}
}

View file

@ -1,115 +0,0 @@
package com.tangem.crypto
import com.tangem.common.extentions.toHexString
import org.spongycastle.asn1.ASN1EncodableVector
import org.spongycastle.asn1.ASN1Integer
import org.spongycastle.asn1.DERSequence
import org.spongycastle.jce.ECNamedCurveTable
import org.spongycastle.jce.spec.ECPrivateKeySpec
import org.spongycastle.jce.spec.ECPublicKeySpec
import java.math.BigInteger
import java.security.KeyFactory
import java.security.PublicKey
import java.security.Signature
internal fun verifySecp256k1(publicKey: ByteArray, message: ByteArray, signature: ByteArray): Boolean {
val signatureInstance = Signature.getInstance("SHA256withECDSA")
val loadedPublicKey = loadPublicKey(publicKey)
signatureInstance.initVerify(loadedPublicKey)
signatureInstance.update(message)
val v = ASN1EncodableVector()
val size = signature.size / 2
v.add(calculateR(signature, size))
v.add(calculateS(signature, size))
val sigDer = DERSequence(v).encoded
return signatureInstance.verify(sigDer)
}
private fun loadPublicKey(publicKeyArray: ByteArray): PublicKey {
val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
val factory = KeyFactory.getInstance("EC", "SC")
val p1 = spec.curve.decodePoint(publicKeyArray)
val keySpec = ECPublicKeySpec(p1, spec)
return factory.generatePublic(keySpec)
}
private fun calculateR(signature: ByteArray, size: Int): ASN1Integer =
ASN1Integer(BigInteger(1, signature.copyOfRange(0, size)))
private fun calculateS(signature: ByteArray, size: Int): ASN1Integer =
ASN1Integer(BigInteger(1, signature.copyOfRange(size, size * 2)))
internal fun signSecp256k1(data: ByteArray, privateKeyArray: ByteArray): ByteArray {
val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
val factory = KeyFactory.getInstance("EC", "SC")
val keySpecP = ECPrivateKeySpec(BigInteger(1, privateKeyArray), spec)
val signature = Signature.getInstance("SHA256withECDSA")
val privateKey = factory.generatePrivate(keySpecP)
signature.initSign(privateKey)
signature.update(data)
val enc = signature.sign()
checkSignatureForErrors(enc)
val res = toByte64(enc)
if (!verifySecp256k1(generatePublicKey(privateKeyArray), data, res)) {
throw Exception("Signature self verify failed - ,enc:" + enc.toHexString() + ",res:" + res.toHexString())
}
return res
}
private fun checkSignatureForErrors(enc: ByteArray) {
if (enc[0].toInt() != 0x30) throw Exception("bad encoding 1")
if (enc[1].toInt() and 0x80 != 0) throw Exception("unsupported length encoding 1")
if (enc[2].toInt() != 0x02) throw Exception("bad encoding 2")
if (enc[3].toInt() and 0x80 != 0) throw Exception("unsupported length encoding 2")
var rLength = enc[3].toInt()
if (enc[4 + rLength].toInt() != 0x02) throw Exception("bad encoding 3")
if (enc[5 + rLength].toInt() and 0x80 != 0)
throw Exception("unsupported length encoding 3")
}
private fun toByte64(enc: ByteArray): ByteArray {
var rLength = enc[3].toInt()
var sLength = enc[5 + rLength].toInt()
val sPos = 6 + rLength
val res = ByteArray(64)
if (rLength <= 32) {
System.arraycopy(enc, 4, res, 32 - rLength, rLength)
rLength = 32
} else if (rLength == 33 && enc[4].toInt() == 0) {
rLength--
System.arraycopy(enc, 5, res, 0, rLength)
} else {
throw Exception("unsupported r-length - r-length:" + rLength.toString() + ",s-length:" + sLength.toString() + ",enc:" + enc.toHexString())
}
if (sLength <= 32) {
System.arraycopy(enc, sPos, res, rLength + 32 - sLength, sLength)
sLength = 32
} else if (sLength == 33 && enc[sPos].toInt() == 0) {
System.arraycopy(enc, sPos + 1, res, rLength, sLength - 1)
} else {
throw Exception("unsupported s-length - r-length:" + rLength.toString() + ",s-length:" + sLength.toString() + ",enc:" + enc.toHexString())
}
return res
}
private fun generatePublicKey(privateKeyArray: ByteArray): ByteArray {
val spec = ECNamedCurveTable.getParameterSpec("secp256k1")
return spec.g.multiply(BigInteger(1, privateKeyArray)).getEncoded(false)
}

View file

@ -0,0 +1,92 @@
package com.tangem.common.extensions
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import java.util.*
class ByteArrayExtensionsTest {
@Test
fun `card Id to Hex String`() {
val hex = "cb22000000027374"
val bytes = byteArrayOf(-53, 34, 0, 0, 0, 2, 115, 116)
assertThat(bytes.toHexString())
.matches(hex)
}
@Test
fun `batch Id to Hex String`() {
val hex = "0029"
val bytes = byteArrayOf(0, 41)
assertThat(bytes.toHexString())
.matches(hex)
}
@Test
fun `curve name to Utf8`() {
val bytes = byteArrayOf(115, 101, 99, 112, 50, 53, 54, 107, 49, 0)
val expected = "secp256k1"
val converted = bytes.toUtf8()
assertThat(converted)
.matches(expected)
}
@Test
fun `blockchain name to Utf8`() {
val bytes = byteArrayOf(69, 84, 72)
val expected = "ETH"
val converted = bytes.toUtf8()
assertThat(converted)
.matches(expected)
}
@Test
fun `bytes to int`() {
val bytes = byteArrayOf(0, 2, 106, 3)
val expected = 158211
assertThat(bytes.toInt())
.isEqualTo(expected)
}
@Test
fun `zero to int`() {
val bytes = byteArrayOf(0)
val expected = 0
assertThat(bytes.toInt())
.isEqualTo(expected)
}
@Test
fun toDate() {
val bytes1 = byteArrayOf(7, -30, 7, 27)
val expected1 = Calendar.getInstance().apply { this.set(2018, 6, 27, 0, 0, 0) }.time
val converted1 = bytes1.toDate()
assertThat(converted1.toString())
.isEqualTo(expected1.toString())
val bytes2 = byteArrayOf(7, -30, 7, 27, 30)
val expected2 = Calendar.getInstance().apply { this.set(2018, 6, 27, 0, 0, 0) }.time
val converted2 = bytes2.toDate()
assertThat(converted2.toString())
.isEqualTo(expected2.toString())
val bytes3 = byteArrayOf(7, -30, 7)
val expected3 = Calendar.getInstance().apply { this.set(2018, 6, 0, 0, 0, 0) }.time
val converted3 = bytes3.toDate()
assertThat(converted3.toString())
.isEqualTo(expected3.toString())
}
@Test
fun `calculate sha512`() {
val bytes = ByteArray(64) { 5 }
val expected = byteArrayOf(
-123, 96, 121, 57, -117, -23, -108, 57, 25, -119, -22, 97, 11, -91,
74, -19, -88, 21, -108, -116, -100, 111, 6, -78, 114, -115, 70, -121, 29, 102, 104, 65,
-21, -68, -111, 121, -51, 109, -94, -24, -40, 108, -25, 70, -26, 61, 38, 12, -127, -34,
-77, -81, 81, -32, -89, -112, -31, -33, 91, 114, 89, 127, -123, -58)
assertThat(bytes.calculateSha512())
.isEqualTo(expected)
}
}

View file

@ -0,0 +1,53 @@
package com.tangem.common.extensions
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class StringExtensionsTest {
@Test
fun `calculate SHA 256 for default PIN 1`() {
val pin = "000000"
val expected = byteArrayOf(-111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115, -10, -111,
34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123, -55, -94, 3)
assertThat(pin.calculateSha256())
.isEqualTo(expected)
}
@Test
fun `calculate SHA 256 for default PIN 2`() {
val pin = "000"
val expected = byteArrayOf(42, -55, -90, 116, 106, -54, 84, 58, -8, -33, -13, -104, -108, -49,
-24, 23, 58, -5, -94, 30, -80, 28, 111, -82, 51, -43, 41, 71, 34, 40, 85, -17)
assertThat(pin.calculateSha256())
.isEqualTo(expected)
}
@Test
fun `calculate SHA 256 for a sample PIN 1`() {
val pin = "999999"
val expected = byteArrayOf(-109, 115, 119, -16, 86, 22, 15, -60, -79, 94, 11, 119, 12, 103,
19, 106, 95, 3, -63, 82, 5, -76, -45, -65, -111, -126, 104, -2, -6, 44, 109, 10)
assertThat(pin.calculateSha256())
.isEqualTo(expected)
}
@Test
fun `calculate SHA 256 for a sample PIN 2`() {
val pin = "999"
val expected = byteArrayOf(-125, -49, -117, 96, -99, -26, 0, 54, -88, 39, 123, -48, -23, 97,
53, 117, 27, -68, 7, -21, 35, 66, 86, -44, -74, 91, -119, 51, 96, 101, 27, -14)
assertThat(pin.calculateSha256())
.isEqualTo(expected)
}
@Test
fun `card ID hex to bytes`() {
val cardId = "cb22000000027374"
val expected = byteArrayOf(-53, 34, 0, 0, 0, 2, 115, 116)
assertThat(cardId.hexToBytes())
.isEqualTo(expected)
}
}

View file

@ -0,0 +1,50 @@
package com.tangem.crypto
import com.google.common.truth.Truth.assertThat
import com.tangem.commands.EllipticCurve
import com.tangem.crypto.CryptoUtils.generatePublicKey
import com.tangem.crypto.CryptoUtils.generateRandomBytes
import com.tangem.crypto.CryptoUtils.verify
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
class CryptoUtilsTest {
@BeforeEach
internal fun setUp() {
CryptoUtils.initCrypto()
}
@Test
fun generateRandomBytesTest() {
val privateKey: ByteArray = generateRandomBytes(32)
assertThat(privateKey)
.hasLength(32)
assertThat(privateKey.sum())
.isNotEqualTo(0)
}
@Test
internal fun verifyEd25519Test() {
val verified = verifySignature_withSampleData(EllipticCurve.Ed25519)
assertThat(verified)
.isTrue()
}
@Test
internal fun verifySecp256k1Test() {
val verified = verifySignature_withSampleData(EllipticCurve.Secp256k1)
assertThat(verified)
.isTrue()
}
private fun verifySignature_withSampleData(curve: EllipticCurve): Boolean {
val privateKey = ByteArray(32) { 1 }
val publicKey = generatePublicKey(privateKey, curve)
val message = ByteArray(64) { 5 }
val signature = message.sign(privateKey, curve)
return verify(publicKey, message, signature, curve)
}
}

View file

@ -45,7 +45,7 @@ class MainActivity : AppCompatActivity() {
}
}
}
}
}
is TaskEvent.Completion -> {
if (taskEvent.error != null) {
if (taskEvent.error is TaskError.UserCancelledError) {
@ -73,14 +73,8 @@ class MainActivity : AppCompatActivity() {
}
private fun createSampleHashes(): Array<ByteArray> {
val hash1 = ByteArray(32)
for (i in 0 until 32) {
hash1[i] = 1
}
val hash2 = ByteArray(32)
for (i in 0 until 32) {
hash2[i] = 2
}
val hash1 = ByteArray(32) { 1 }
val hash2 = ByteArray(32) { 2 }
return arrayOf(hash1, hash2)
}
}