Xamarin iOS EC加密SECP256r1与SHA256摘要公钥长度

hc8w905p  于 5个月前  发布在  iOS
关注(0)|答案(1)|浏览(71)

我正在用公钥和私钥实现生物认证。
在密钥对的示例化过程中,公钥保存在服务器上,私钥保存在设备上的密钥库中。
然后向设备发送一个质询,由私钥签名,并在服务器上用公钥进行验证。
我能够在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的字节数组,然后将其转换为124字符的Base64字符串。
现在我正尝试在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,转换为88字符长的Base64字符串。
我试着用KeySizeInBits来改变公钥的长度,但是除了256之外的任何大小都会导致generatedPublicKeygeneratedPrivateKey变成null
为什么我会得到不同长度的公钥?

mkshixfv

mkshixfv1#

好吧,我找到了一个很老的thread,其中一条评论指向了一个解决方案:
通过反复试验,我发现必须向原始公钥字节添加标准的ASN.1报头
通过使用Android实现生成几个公钥,我发现它们都以相同的字符开头。

MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE

字符串
iOS公钥短91-65=26字节,所以我从Android公钥中取出第一个相同的26字节,然后将它们与iOS实现中的65字节公钥连接起来,得到91字节公钥。
服务器端确认公钥结构正确,现在一切都按预期工作。
我希望我没有搞砸任何事情,因为我不是一个加密Maven,但如果它是一个标准的标题,我想这是确定的。
如果有人感兴趣的话:

private readonly byte[] ASN1_HEADER = new byte[] { 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0 };

private byte[] ConcatenateHeaderToPublicKey(byte[] publicKey)
{
    byte[] result = new byte[ASN1_HEADER.Length + publicKey.Length];
    Buffer.BlockCopy(ASN1_HEADER, 0, result, 0, ASN1_HEADER.Length);
    Buffer.BlockCopy(publicKey, 0, result, ASN1_HEADER.Length, publicKey.Length);
    return result;
}

相关问题