Xamarin iOS与Android生成SECP256r1公钥长度不一致问题
问题
基于公钥私钥实现生物认证功能:密钥对生成后公钥存储在服务器,私钥保存在设备密钥库;服务器下发挑战,设备用私钥签名后由服务器验签。
已在Xamarin.Android中完成实现,生成密钥对代码如下:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmEc, "AndroidKeyStore"); keyPairGenerator.Initialize(new KeyGenParameterSpec.Builder(alias, KeyStorePurpose.Sign) .SetDigests(KeyProperties.DigestSha256) .SetAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) .SetUserAuthenticationRequired(true) .Build()); keyPairGenerator.GenerateKeyPair();
通过publicKey.GetEncoded()获取的公钥字节数组长度为91,转Base64后为124字符。
现在尝试在Xamarin.iOS中实现相同功能,代码如下:
using (SecAccessControl access = new SecAccessControl(SecAccessible.WhenUnlockedThisDeviceOnly, SecAccessControlCreateFlags.BiometryCurrentSet | SecAccessControlCreateFlags.PrivateKeyUsage)) { SecKeyGenerationParameters parameters = new SecKeyGenerationParameters { KeyType = SecKeyType.EC, ApplicationTag = alias, CanSign = true, AccessControl = access, TokenID = SecTokenID.SecureEnclave // secp256r1? }; SecKey.GenerateKeyPair(parameters.Dictionary, out SecKey generatedPublicKey, out SecKey generatedPrivateKey); }
通过publicKey.GetExternalRepresentation().ToArray()获取的公钥字节数组长度仅为65,转Base64后为88字符。尝试修改KeySizeInBits,除256外的其他值都会导致生成的公钥、私钥为null。请问为何两者生成的公钥长度不一致?
原因分析与解决方法
公钥格式差异导致长度不同
Android中publicKey.GetEncoded()返回的是X.509格式的DER编码公钥(即SubjectPublicKeyInfo结构),该结构包含算法标识符、曲线参数等额外元数据,因此总长度为91字节。而iOS中GetExternalRepresentation()返回的是未压缩的原始EC公钥:仅包含1字节前缀0x04,加上64字节的x、y坐标,总共65字节,没有额外元数据,所以长度更短。
实现iOS与Android公钥格式兼容的方法
你可以将iOS生成的65字节原始公钥转换为X.509 DER格式,这样就能和Android生成的公钥长度一致,且能被服务器正确解析。示例代码如下:
// originalPublicKeyBytes 为iOS获取的65字节原始公钥 var ecParams = new ECParameters { Curve = ECCurve.NamedCurves.nistP256 }; using var ecPublicKey = ECDsa.Create(ecParams); ecPublicKey.ImportSubjectPublicKeyInfo(originalPublicKeyBytes, out _); byte[] x509FormattedPublicKey = ecPublicKey.ExportSubjectPublicKeyInfo(); // x509FormattedPublicKey 就是与Android一致的91字节X.509格式公钥
关于KeySizeInBits的问题
iOS Secure Enclave仅支持特定的EC曲线,secp256r1对应的密钥长度就是256位,其他长度不被Secure Enclave支持,因此修改为其他值会导致密钥生成失败,属于正常现象。
内容的提问来源于stack exchange,提问作者Derorrist

