网站建设行规,在线编程的网站,装修设计公司加盟,营销型网站商城移动端 [Android iOS] 压缩 ECDSA PublicKey AndroidiOS 使用 Android KeyStore 和 iOS 的 Secure Enclave 提供的安全能力使用 P-256 来对 API 请求进行签名#xff0c;服务器端再进行验证。 但是发现不论是 iOS 还是安卓都没有提供一个便捷的方式从 iOS 的SecKeyCopyE… 移动端 [Android iOS] 压缩 ECDSA PublicKey AndroidiOS 使用 Android KeyStore 和 iOS 的 Secure Enclave 提供的安全能力使用 P-256 来对 API 请求进行签名服务器端再进行验证。 但是发现不论是 iOS 还是安卓都没有提供一个便捷的方式从 iOS 的SecKeyCopyExternalRepresentation(SecKeyCopyPublicKey) 和 Android 的 KeyPair 中得到 33-bytes 的 compressed public key。
压缩公钥Compressed Public Key是一种公钥编码方式可以将 ECC椭圆曲线密码学公钥从 64 个字节压缩为 33 个字节。这种编码方式由一个字节的标识符和32个字节的公钥坐标的一部分y坐标组成从而实现了公钥的压缩。在使用压缩公钥时可以减少传输的数据量和存储空间同时保持相同的安全性和加密效果。压缩公钥广泛应用于比特币、以太坊等区块链领域中。
compressed_public_key y is even?0x02:0x03 x
Android
private fun secp256r1JKeyPair(packageManager: PackageManager,alias: String,throwIfNotExists: Boolean false,
): KeyPair {val ks: KeyStore KeyStore.getInstance(storeProvider).apply { load(null) }val keyPair: KeyPair if (ks.containsAlias(alias)) {val entry ks.getEntry(alias, null)if (entry !is KeyStore.PrivateKeyEntry) {throw TypeCastException()}KeyPair(entry.certificate.publicKey, entry.privateKey)} else if (throwIfNotExists) {throw KeyStoreException(No key was found with the alias $alias.)} else {val kpg: KeyPairGenerator KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, storeProvider)var properties KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFYval parameterSpec KeyGenParameterSpec.Builder(alias, properties).apply {setAlgorithmParameterSpec(ECGenParameterSpec(secp256r1))setDigests(KeyProperties.DIGEST_SHA256)if (Build.VERSION.SDK_INT Build.VERSION_CODES.P hasStrongBox(packageManager)) {setIsStrongBoxBacked(true)}}.build()kpg.initialize(parameterSpec)kpg.generateKeyPair()}return keyPair
}OptIn(ExperimentalUnsignedTypes::class)
fun bnUByteArrayToUByteArray(bnUByteArray: UByteArray, expectLength: Int): UByteArray {if (bnUByteArray.size expectLength 1) {return bnUByteArray.sliceArray(1..expectLength)}if (bnUByteArray.size expectLength) {return UByteArray(expectLength - bnUByteArray.size) { UByte.MIN_VALUE } bnUByteArray}return bnUByteArray
}OptIn(ExperimentalUnsignedTypes::class)
fun secp256r1PublicKey(packageManager: PackageManager,alias: String
): UByteArray {val kp secp256r1JKeyPair(packageManager, alias)val publicKey kp.public as ECPublicKey;val point publicKey.wval x: BigInteger point.affineXval y: BigInteger point.affineYval xBytes: UByteArray bnUByteArrayToUByteArray(x.toByteArray().toUByteArray(), 32)val yFLag UByteArray(1)yFLag[0] (if (y.testBit(0)) 0x03 else 0x02).toUByte()return yFLag xBytes
}OptIn(ExperimentalUnsignedTypes::class)
fun secp256r1Sign(packageManager: PackageManager,alias: String,payload: ByteArray
): UByteArray {val privateKey secp256r1JKeyPair(packageManager, alias).privateval signature Signature.getInstance(signatureAlgorithm).run {initSign(privateKey)update(payload)sign()}val seq DERSequence.fromByteArray(signature) as DLSequenceval r bnUByteArrayToUByteArray((seq.getObjectAt(0) as ASN1Integer).value.toByteArray().toUByteArray(), 32)val s bnUByteArrayToUByteArray((seq.getObjectAt(1) as ASN1Integer).value.toByteArray().toUByteArray(), 32)return r s
}OptIn(ExperimentalUnsignedTypes::class)
private fun byteArrayToHexString(byteArray: UByteArray): String {return byteArray.joinToString(separator ) { it.toString(16).padStart(2, 0) }
}iOS
static func secp256r1Key(name: String, requiresBiometry: Bool false) throws - SecKey {let flags: SecAccessControlCreateFlags requiresBiometry ? [.privateKeyUsage, .userPresence] : .privateKeyUsagelet access SecAccessControlCreateWithFlags(kCFAllocatorDefault,kSecAttrAccessibleWhenUnlockedThisDeviceOnly,flags,nil)!let tag name.data(using: .utf8)!let attributes: [String: Any] [kSecAttrKeyType as String : kSecAttrKeyTypeEC,kSecAttrKeySizeInBits as String : 256,kSecAttrTokenID as String : kSecAttrTokenIDSecureEnclave,kSecPrivateKeyAttrs as String : [kSecAttrIsPermanent as String : true,kSecAttrApplicationTag as String : tag,kSecAttrAccessControl as String : access] as [String : Any]]var error: UnmanagedCFError?guard let privateKey SecKeyCreateRandomKey(attributes as CFDictionary, error) else {throw error!.takeRetainedValue()}return privateKey
}static func getCompressedPublicKey(key: SecKey) throws - Data {guard let publicKeyData SecKeyCopyExternalRepresentation(SecKeyCopyPublicKey(key)!, nil) as? Data else {throw NSError()}let x publicKeyData.dropFirst().prefix(32)let y publicKeyData.subdata(in: Range(33...64))return Data([0x02 | (y.last! 0x01)]) x
}static func secp256r1Sign(name: String, payload: Data) - Data {let key secp256r1Key(name: name)var error: UnmanagedCFError?let asn1signature SecKeyCreateSignature(key!, .ecdsaSignatureMessageX962SHA256, payload as CFData, error)! as Datalet signature try! ECSignature(asn1: asn1signature)return signature.r signature.s
}