diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt index c24d3ed..affbfaa 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/oid/OpenIdProvider.kt @@ -15,7 +15,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule import com.fasterxml.jackson.module.kotlin.convertValue import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.ownd_project.tw2023_wallet_android.utils.SigningOption -import com.ownd_project.tw2023_wallet_android.utils.KeyPairUtil +import com.ownd_project.tw2023_wallet_android.utils.KeyUtil import okhttp3.FormBody import okhttp3.OkHttpClient import okhttp3.Request @@ -205,7 +205,7 @@ class OpenIdProvider(val uri: String, val option: SigningOption = SigningOption( val nonce = authRequest.nonce val SEC_IN_MS = 1000 - val subJwk = KeyPairUtil.keyPairToPublicJwk(keyPair, option) + val subJwk = KeyUtil.keyPairToPublicJwk(keyPair, option) // todo: support rsa key val jwk = object : ECPublicJwk { override val kty = subJwk["kty"]!! diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/shared/JwtVpJsonGeneratorImpl.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/shared/JwtVpJsonGeneratorImpl.kt index 104c52c..0ead917 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/shared/JwtVpJsonGeneratorImpl.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/ui/shared/JwtVpJsonGeneratorImpl.kt @@ -8,6 +8,7 @@ import com.ownd_project.tw2023_wallet_android.oid.JwtVpJsonPayloadOptions import com.ownd_project.tw2023_wallet_android.signature.JWT import com.ownd_project.tw2023_wallet_android.utils.SigningOption import com.ownd_project.tw2023_wallet_android.utils.KeyPairUtil +import com.ownd_project.tw2023_wallet_android.utils.KeyUtil import java.security.PublicKey class JwtVpJsonGeneratorImpl(private val keyAlias: String = Constants.KEY_PAIR_ALIAS_FOR_KEY_JWT_VP_JSON) : @@ -48,7 +49,7 @@ class JwtVpJsonGeneratorImpl(private val keyAlias: String = Constants.KEY_PAIR_A } val publicKey: PublicKey = KeyPairUtil.getPublicKey(keyAlias) ?: throw IllegalStateException("Public key not found for alias: $keyAlias") - val jwk = KeyPairUtil.publicKeyToJwk(publicKey, SigningOption()) + val jwk = KeyUtil.publicKeyToJwk(publicKey, SigningOption()) return jwk } } \ No newline at end of file diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/utils/KeyPairUtil.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/utils/KeyPairUtil.kt index 4219fd3..13f615f 100644 --- a/app/src/main/java/com/ownd_project/tw2023_wallet_android/utils/KeyPairUtil.kt +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/utils/KeyPairUtil.kt @@ -138,65 +138,6 @@ object KeyPairUtil { return keyFactory.generatePublic(keySpec) } - fun correctBytes(value: BigInteger): ByteArray { - /* - BigInteger の toByteArray() メソッドは、数値をバイト配列に変換しますが、 - この数値が正の場合、最上位バイトが符号ビットとして解釈されることを避けるために、追加のゼロバイトが先頭に挿入されることがあります。 - これは、数値が正で、最上位バイトが 0x80 以上の場合(つまり、最上位ビットが 1 の場合)に起こります。 - その結果、期待していた 32 バイトではなく 33 バイトの配列が得られることがあります。 - - 期待する 32 バイトの配列を得るには、返されたバイト配列から余分なゼロバイトを取り除くか、 - または正確なバイト長を指定して配列を生成する必要があります。 - */ - val bytes = value.toByteArray() - return if (bytes.size == 33 && bytes[0] == 0.toByte()) bytes.copyOfRange( - 1, - bytes.size - ) else bytes - } - - private fun publicKeyToJwk( - ecPublicKey: ECPublicKey, - option: SigningOption - ): Map { - val ecPoint: ECPoint = ecPublicKey.w - val x = correctBytes(ecPoint.affineX).toBase64Url() - val y = correctBytes(ecPoint.affineY).toBase64Url() - - // return """{"kty":"EC","crv":"P-256","x":"$x","y":"$y"}""" // crvは適宜変更してください - return mapOf( - "kty" to "EC", - "crv" to option.signingCurve, - "x" to x, - "y" to y - ) - } - - private fun publicKeyToJwk(rsaPublicKey: RSAPublicKey): Map { - val n = Base64.getUrlEncoder().encodeToString(rsaPublicKey.modulus.toByteArray()) - val e = Base64.getUrlEncoder().encodeToString(rsaPublicKey.publicExponent.toByteArray()) - - // return """{"kty":"RSA","n":"$n","e":"$e"}""" - return mapOf( - "kty" to "RSA", - "n" to n, - "e" to e - ) - } - - fun keyPairToPublicJwk(keyPair: KeyPair, option: SigningOption): Map { - val publicKey: PublicKey = keyPair.public - return publicKeyToJwk(publicKey, option) - } - - fun publicKeyToJwk(publicKey: PublicKey, option: SigningOption): Map { - return when (publicKey) { - is RSAPublicKey -> publicKeyToJwk(publicKey) - is ECPublicKey -> publicKeyToJwk(publicKey, option) - else -> throw IllegalArgumentException("Unsupported Key Type: ${publicKey::class.java.name}") - } - } - // todo move to anywhere else fun verifyJwt(jwkJson: Map, jwt: String): Boolean { val publicKey = createPublicKey(jwkJson) diff --git a/app/src/main/java/com/ownd_project/tw2023_wallet_android/utils/KeyUtil.kt b/app/src/main/java/com/ownd_project/tw2023_wallet_android/utils/KeyUtil.kt new file mode 100644 index 0000000..3ddf610 --- /dev/null +++ b/app/src/main/java/com/ownd_project/tw2023_wallet_android/utils/KeyUtil.kt @@ -0,0 +1,73 @@ +package com.ownd_project.tw2023_wallet_android.utils + +import com.ownd_project.tw2023_wallet_android.signature.toBase64Url +import java.math.BigInteger +import java.security.KeyPair +import java.security.PublicKey +import java.security.interfaces.ECPublicKey +import java.security.interfaces.RSAPublicKey +import java.security.spec.ECPoint +import java.util.Base64 + +object KeyUtil { + + fun correctBytes(value: BigInteger): ByteArray { + /* + BigInteger の toByteArray() メソッドは、数値をバイト配列に変換しますが、 + この数値が正の場合、最上位バイトが符号ビットとして解釈されることを避けるために、追加のゼロバイトが先頭に挿入されることがあります。 + これは、数値が正で、最上位バイトが 0x80 以上の場合(つまり、最上位ビットが 1 の場合)に起こります。 + その結果、期待していた 32 バイトではなく 33 バイトの配列が得られることがあります。 + + 期待する 32 バイトの配列を得るには、返されたバイト配列から余分なゼロバイトを取り除くか、 + または正確なバイト長を指定して配列を生成する必要があります。 + */ + val bytes = value.toByteArray() + return if (bytes.size == 33 && bytes[0] == 0.toByte()) bytes.copyOfRange( + 1, + bytes.size + ) else bytes + } + + private fun publicKeyToJwk( + ecPublicKey: ECPublicKey, + option: SigningOption + ): Map { + val ecPoint: ECPoint = ecPublicKey.w + val x = correctBytes(ecPoint.affineX).toBase64Url() + val y = correctBytes(ecPoint.affineY).toBase64Url() + + // return """{"kty":"EC","crv":"P-256","x":"$x","y":"$y"}""" // crvは適宜変更してください + return mapOf( + "kty" to "EC", + "crv" to option.signingCurve, + "x" to x, + "y" to y + ) + } + + private fun publicKeyToJwk(rsaPublicKey: RSAPublicKey): Map { + val n = Base64.getUrlEncoder().encodeToString(rsaPublicKey.modulus.toByteArray()) + val e = Base64.getUrlEncoder().encodeToString(rsaPublicKey.publicExponent.toByteArray()) + + // return """{"kty":"RSA","n":"$n","e":"$e"}""" + return mapOf( + "kty" to "RSA", + "n" to n, + "e" to e + ) + } + + fun keyPairToPublicJwk(keyPair: KeyPair, option: SigningOption): Map { + val publicKey: PublicKey = keyPair.public + return publicKeyToJwk(publicKey, option) + } + + fun publicKeyToJwk(publicKey: PublicKey, option: SigningOption): Map { + return when (publicKey) { + is RSAPublicKey -> publicKeyToJwk(publicKey) + is ECPublicKey -> publicKeyToJwk(publicKey, option) + else -> throw IllegalArgumentException("Unsupported Key Type: ${publicKey::class.java.name}") + } + } + +}