代码之家  ›  专栏  ›  技术社区  ›  Derorrist

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

  •  0
  • Derorrist  · 技术社区  · 2 年前

    我正在使用公钥和私钥实现生物特征验证。

    在密钥对的实例化过程中,公钥保存在服务器上,私钥保存在设备上的密钥库中。

    然后,向设备发送一个质询,由私钥签名,并在服务器上使用公钥进行验证。

    我能够在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 ,翻译为 88 个字符长的Base64字符串。

    我尝试用更改公钥的长度 KeySizeInBits ,但除了 256 原因 generatedPublicKey generatedPrivateKey 将来 null

    为什么我要获得不同长度的公钥?

    0 回复  |  直到 2 年前
        1
  •  0
  •   Derorrist    2 年前

    好的,所以我发现了一个很老的 thread 其中一条评论为我指出了一个解决方案:

    经过反复尝试,我发现我必须添加一个标准的ASN.1 OID 原始公钥字节的标头

    通过使用生成几个公钥 Android 实现时,我看到它们都以相同的字符开头。

    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
    

    这个 iOS 公钥是 91-65=26 字节短,所以我取了第一个相同的 26 的字节 安卓 公钥,然后将它们与 65 的字节公钥 iOS 实现以获得 91 字节公钥。

    服务器端确认公钥的结构正确,现在一切都按预期进行。

    我希望我没有搞砸任何事情,因为我不是加密专家,但如果这是一个标准的头,我想这没关系。

    如果有人感兴趣,请执行:

    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;
    }