2

问题如下:

  • 我在 Android (Xamarin.Droid) 中生成密钥:

     public IPublicKey CreateKey(string keyID)
     {
        /*KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
                 KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
        keyPairGenerator.initialize(
                new KeyGenParameterSpec.Builder(
                        "key1",
                        KeyProperties.PURPOSE_SIGN)
                        .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                        .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
                        .build());
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        Signature signature = Signature.getInstance("SHA256withRSA/PSS");
        signature.initSign(keyPair.getPrivate());
    
         // The key pair can also be obtained from the Android Keystore any time as follows:
         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
                    keyStore.load(null);
                    PrivateKey privateKey = (PrivateKey)keyStore.getKey("key1", null);
                    PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey();*/
    
    
        //App.Current.MainPage.DisplayAlert("Info", "Creating a new key pair", "Ok");
        // UTILIZANDO RSA
        KeyPairGenerator kpg = 
        KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, KEYSTORE_NAME);
        kpg.Initialize(
            new KeyGenParameterSpec.Builder(keyID,
            KeyStorePurpose.Sign)
            .SetSignaturePaddings(KeyProperties.SignaturePaddingRsaPss)
            .SetDigests(KeyProperties.DigestSha1)
            .Build()
            );
    
        KeyPair keyPair = kpg.GenerateKeyPair();
    
        Log.Debug(TAG, "New key created for fingerprint authentication");
    
        return keyPair.Public;
    }
    
  • 然后我生成一个签名:

        KeyStore.PrivateKeyEntry PKentry = 
        (KeyStore.PrivateKeyEntry)_keystore.GetEntry(keyID, null);
        IPublicKey pk = (IPublicKey)PKentry.Certificate.PublicKey;
        //this.pk = pk;
        privKey = PKentry.PrivateKey;
    
        //cipher.Init(Cipher.EncryptMode, privKey);
        //byte[] output = cipher.DoFinal(Encoding.UTF8.GetBytes(input));
        //String s = new string(cipher.DoFinal(input));
    
        // signature
        Signature sig = Signature.GetInstance("SHA1withRSA/PSS");
        sig.InitSign(privKey);
        byte[] inputDataToSign = Encoding.UTF8.GetBytes(input);
        sig.Update(inputDataToSign);
        byte[] signatureBytes = sig.Sign();
    
  • 我将密钥和签名发送到 ASP.net wep API 2 服务器。客户端响应生成:

     RegistrationResponse registrationResponse = new RegistrationResponse();
     string fcparams = Utils.Base64Encode(JsonConvert.SerializeObject(finalChallengeParams));
      registrationResponse.fcParams = fcparams;
      byte[] signedData = sign(fcparams, registrationRequest.username, facetID);
     registrationResponse.signedData = signedData;
     registrationResponse.Base64key = convertPublicKeyToString(publicKey);
     ...
     ...
    private string convertPublicKeyToString(IPublicKey publicKey)
    {
        string publicKeyString = Base64.EncodeToString(publicKey.GetEncoded(), 0);
    
     return publicKeyString;
      }
    

我使用 Refit Nugget 发送它。这是我在服务器端收到 HTTPRequest 时使用的代码:

[Route("regResponse/")]
    [HttpPost]
    public IHttpActionResult ProcessClientRegistrationResponse([FromBody] RegistrationResponse registrationResponse) 
    {


        //byte[] publicKeyBytes = Convert.FromBase64String(registrationResponse.Base64key);
        byte[] publicKeyBytes = registrationResponse.Base64key;
        AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);

        RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;

        RSAParameters rsaParameters = new RSAParameters();
        rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
        rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();

        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(rsaParameters);

        /*****/

        string alg = rsa.SignatureAlgorithm;
        byte[] signedData = registrationResponse.signedData;
        byte[] fcParamsBytes = Encoding.UTF8.GetBytes(registrationResponse.fcParams);

        RSACng rsaCng = new RSACng();
        rsaCng.ImportParameters(rsaParameters);

        SHA1Managed hash = new SHA1Managed();
        byte[] hashedData;
        hashedData = hash.ComputeHash(signedData);


        /*********/

        bool rsaCngDataOk1 = rsaCng.VerifyData(fcParamsBytes, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
        bool rsaCngDataOk2 = rsaCng.VerifyData(fcParamsBytes, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
        bool rsaCngDataOk3 = rsaCng.VerifyData(hashedData, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
        bool rsaCngDataOk4 = rsaCng.VerifyData(hashedData, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);

        bool rsaCngHashOk1 = rsaCng.VerifyHash(hashedData, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);

        bool dataOK1 = rsa.VerifyData(fcParamsBytes, new SHA1CryptoServiceProvider(), signedData);
        bool dataOk2 = rsa.VerifyData(fcParamsBytes, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);

        bool hashOk = rsa.VerifyHash(hashedData, CryptoConfig.MapNameToOID("SHA1"), signedData);

        return Ok(true);

    }

每个布尔值都是错误的。我认为问题显然出在公钥上。问题是,

  1. 方法 publickey.encode() 做我想的吗?我认为它将我的公钥转换为 byte[] 表示(来源:Android 开发人员 Key Info

  2. 我是否将收到的密钥的字节 [] 表示形式转换为正确的 RSA 密钥?

  3. 算法有问题吗?我不这么认为,但我们永远不知道...

我找不到解决方案。我搜索了从 .net 或 c# 中的字符串导入公钥的方法,以及将 Android 公钥导出为字符串或字节 [] 的方法,但对于这个具体问题没有太大帮助......

4

1 回答 1

0

@James K Polk 给了我解决方案。显然 C# 不适用于 PSS 填充。我只需要将其更改为 PKCS1。我也将摘要算法更改为 SHA512。

于 2017-11-17T11:27:49.310 回答