From 8b3a0019ad913700df3c3d85698f7a19a62c2a93 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 11 Jun 2024 18:42:17 +0545 Subject: [PATCH 1/2] Add get certificate function in kotlin --- .../astrox/secure_p256_plugin/SecureP256Plugin.kt | 13 +++++++++++++ example/lib/main.dart | 12 +++++++++++- lib/p256_method_channel.dart | 9 +++++++++ lib/p256_platform_interface.dart | 4 ++++ lib/secp256r1.dart | 8 ++++++++ lib/src/constants.dart | 1 + 6 files changed, 46 insertions(+), 1 deletion(-) diff --git a/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt b/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt index 50143d4..919aa71 100644 --- a/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt +++ b/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt @@ -13,6 +13,7 @@ import io.flutter.plugin.common.MethodChannel.Result import org.bouncycastle.jce.provider.BouncyCastleProvider import org.conscrypt.Conscrypt import java.security.* +import java.security.cert.Certificate import java.security.spec.ECGenParameterSpec import java.security.spec.EncodedKeySpec import java.security.spec.X509EncodedKeySpec @@ -54,6 +55,12 @@ class SecureP256Plugin : FlutterPlugin, MethodCallHandler { result.success(keyPair.public.encoded) } + "getCertificate" -> { + val alias = call.argument("tag")!! + val certificate = getCertificate(alias) + result.success(certificate.encoded) + } + "sign" -> { val cAlias = call.argument("tag")!! val payload = call.argument("payload")!! @@ -185,6 +192,12 @@ class SecureP256Plugin : FlutterPlugin, MethodCallHandler { return agreement.generateSecret() } + private fun getCertificate(alias: String): Certificate { + val ks: KeyStore = KeyStore.getInstance(storeProvider).apply { load(null) } + val entry = obtainPrivateKeyEntryFromAlias(alias, ks) + return entry.certificate as Certificate + } + // private fun hasStrongBox(): Boolean { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { // return applicationContext!!.packageManager.hasSystemFeature( diff --git a/example/lib/main.dart b/example/lib/main.dart index d8abe19..3fadf3a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,7 +22,7 @@ class _MyAppState extends State { String _publicKey = 'Unknown'; String _signed = 'Unknown'; bool? _verified; - String? _sharedSecret, _decrypted; + String? _certificate, _sharedSecret, _decrypted; Tuple2? _encrypted; final _payloadTEC = TextEditingController(text: 'Hello world'); @@ -42,6 +42,7 @@ class _MyAppState extends State { body: ListView( children: [ SelectableText('getPublicKey: $_publicKey\n'), + SelectableText('certificate: $_certificate\n'), SelectableText('sign: $_signed\n'), SelectableText('verify: $_verified\n'), SelectableText('sharedSecret: $_sharedSecret\n'), @@ -75,6 +76,15 @@ class _MyAppState extends State { }, child: const Text('getPublicKey'), ), + ElevatedButton( + onPressed: () { + SecureP256.getCertificate( + alias, + Uint8List.fromList(utf8.encode(_verifyPayload)), + ).then((r) => setState(() => _certificate = r.toString())); + }, + child: const Text('getCertificate'), + ), ElevatedButton( onPressed: () { SecureP256.sign( diff --git a/lib/p256_method_channel.dart b/lib/p256_method_channel.dart index 03f817e..5fcc0a4 100644 --- a/lib/p256_method_channel.dart +++ b/lib/p256_method_channel.dart @@ -19,6 +19,15 @@ class SecureP256Channel extends SecureP256Platform { return keyBytes; } + @override + Future getCertificate(String tag, Uint8List payload) async { + final signature = await methodChannel.invokeMethod( + Methods.getCertificate, + {'tag': tag, 'payload': payload}, + ); + return signature; + } + @override Future sign(String tag, Uint8List payload) async { final signature = await methodChannel.invokeMethod( diff --git a/lib/p256_platform_interface.dart b/lib/p256_platform_interface.dart index 2b6775d..a58a03b 100644 --- a/lib/p256_platform_interface.dart +++ b/lib/p256_platform_interface.dart @@ -29,6 +29,10 @@ abstract class SecureP256Platform extends PlatformInterface { return _instance.getPublicKey(tag); } + Future getCertificate(String tag, Uint8List payload) { + return _instance.getCertificate(tag, payload); + } + Future sign(String tag, Uint8List payload) { return _instance.sign(tag, payload); } diff --git a/lib/secp256r1.dart b/lib/secp256r1.dart index 348ed08..8deeee5 100644 --- a/lib/secp256r1.dart +++ b/lib/secp256r1.dart @@ -23,6 +23,14 @@ class SecureP256 { } } + static Future getCertificate(String tag, Uint8List payload) async { + assert(tag.isNotEmpty); + assert(payload.isNotEmpty); + final certificate = + await SecureP256Platform.instance.getCertificate(tag, payload); + return certificate; + } + static Future sign(String tag, Uint8List payload) async { assert(tag.isNotEmpty); assert(payload.isNotEmpty); diff --git a/lib/src/constants.dart b/lib/src/constants.dart index 4f1d1b5..ae87509 100644 --- a/lib/src/constants.dart +++ b/lib/src/constants.dart @@ -3,6 +3,7 @@ class Methods { static const getPublicKey = 'getPublicKey'; static const sign = 'sign'; + static const getCertificate = 'getCertificate'; static const verify = 'verify'; static const getSharedSecret = 'getSharedSecret'; } From 84964083501d7c79e66c1ec40853ae7a55050f9f Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 12 Jun 2024 19:00:32 +0545 Subject: [PATCH 2/2] feat: Read X509Certificate properly in android --- .../secure_p256_plugin/SecureP256Plugin.kt | 4 ++-- example/lib/main.dart | 19 +++++++++++++------ lib/p256_method_channel.dart | 4 ++-- lib/p256_platform_interface.dart | 4 ++-- lib/secp256r1.dart | 6 ++---- pubspec.yaml | 6 ++++-- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt b/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt index 919aa71..7af6a3f 100644 --- a/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt +++ b/android/src/main/kotlin/com/astrox/secure_p256_plugin/SecureP256Plugin.kt @@ -1,10 +1,10 @@ package com.astrox.secure_p256_plugin import android.content.Context -//import android.content.pm.PackageManager import android.os.Build import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties +import android.util.Base64 import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel @@ -58,7 +58,7 @@ class SecureP256Plugin : FlutterPlugin, MethodCallHandler { "getCertificate" -> { val alias = call.argument("tag")!! val certificate = getCertificate(alias) - result.success(certificate.encoded) + result.success(Base64.encodeToString(certificate.encoded, Base64.NO_WRAP)) } "sign" -> { diff --git a/example/lib/main.dart b/example/lib/main.dart index 3fadf3a..e4f00d8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,11 +1,14 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:agent_dart/identity/p256.dart'; +import 'package:agent_dart/agent_dart.dart'; +import 'package:asn1lib/asn1lib.dart' as asn1lib; import 'package:convert/convert.dart'; import 'package:flutter/material.dart'; -import 'package:secp256r1/secp256r1.dart'; import 'package:tuple/tuple.dart'; +import 'package:x509/x509.dart' as x509; + +import 'package:secp256r1/secp256r1.dart'; void main() { runApp(const MyApp()); @@ -78,10 +81,14 @@ class _MyAppState extends State { ), ElevatedButton( onPressed: () { - SecureP256.getCertificate( - alias, - Uint8List.fromList(utf8.encode(_verifyPayload)), - ).then((r) => setState(() => _certificate = r.toString())); + SecureP256.getCertificate(alias).then( + (r) => setState(() { + final decoded = base64Decode(r.toString()); + final seq = asn1lib.ASN1Sequence.fromBytes(decoded); + final cert = x509.X509Certificate.fromAsn1(seq); + _certificate = cert.toString(); + }), + ); }, child: const Text('getCertificate'), ), diff --git a/lib/p256_method_channel.dart b/lib/p256_method_channel.dart index 5fcc0a4..7f6bdaa 100644 --- a/lib/p256_method_channel.dart +++ b/lib/p256_method_channel.dart @@ -20,10 +20,10 @@ class SecureP256Channel extends SecureP256Platform { } @override - Future getCertificate(String tag, Uint8List payload) async { + Future getCertificate(String tag) async { final signature = await methodChannel.invokeMethod( Methods.getCertificate, - {'tag': tag, 'payload': payload}, + {'tag': tag}, ); return signature; } diff --git a/lib/p256_platform_interface.dart b/lib/p256_platform_interface.dart index a58a03b..babaadd 100644 --- a/lib/p256_platform_interface.dart +++ b/lib/p256_platform_interface.dart @@ -29,8 +29,8 @@ abstract class SecureP256Platform extends PlatformInterface { return _instance.getPublicKey(tag); } - Future getCertificate(String tag, Uint8List payload) { - return _instance.getCertificate(tag, payload); + Future getCertificate(String tag) { + return _instance.getCertificate(tag); } Future sign(String tag, Uint8List payload) { diff --git a/lib/secp256r1.dart b/lib/secp256r1.dart index 8deeee5..93a3edb 100644 --- a/lib/secp256r1.dart +++ b/lib/secp256r1.dart @@ -23,11 +23,9 @@ class SecureP256 { } } - static Future getCertificate(String tag, Uint8List payload) async { + static Future getCertificate(String tag) async { assert(tag.isNotEmpty); - assert(payload.isNotEmpty); - final certificate = - await SecureP256Platform.instance.getCertificate(tag, payload); + final certificate = await SecureP256Platform.instance.getCertificate(tag); return certificate; } diff --git a/pubspec.yaml b/pubspec.yaml index 0862a3c..14d2c6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,15 +5,17 @@ version: 0.1.0-dev.7 repository: https://github.com/AstroxNetwork/flutter_secp256r1 environment: - sdk: '>=2.13.0 <4.0.0' - flutter: '>=2.0.0' + sdk: ">=2.13.0 <4.0.0" + flutter: ">=2.0.0" dependencies: + asn1lib: ^1.5.2 flutter: sdk: flutter agent_dart: ^1.0.0-dev.8 plugin_platform_interface: ^2.0.2 tuple: ^2.0.0 + x509: ^0.2.4+2 dev_dependencies: flutter_test: