为什么 .NET RSACryptoServiceProvider 会引发"Safe handle has been closed"异常?



以下方法用于使用"SHA1"根据公钥验证数据。第一次调用该方法时工作正常。然而,当该方法被调用第二次和随后的时

isVerified = RSA.VerifyData(tokenData, CryptoConfig.MapNameToOID(hashType), signature);

导致此异常

{"Safe handle has been closed"} System.Exception {System.ObjectDisposedException}

想想我可能做错了什么?

internal static bool VerifyTokenData(byte[] tokenData, byte[] signature, string hashType)
{
  try
  {
    bool isVerified = false;
    using (RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)CompanyAuthentication.publicKey)
    {
      isVerified = RSA.VerifyData(tokenData, CryptoConfig.MapNameToOID(hashType), signature);
    }
    return isVerified;
  }
  catch (CryptographicException cryptoExc)
  {
    throw new InvalidOperationException("Exception verifying token data", cryptoExc);
  }
  catch (Exception exc)
  {
    throw new InvalidOperationException("Exception verifying token data", exc);
  }
}

使用将使用的公钥加载到类变量中

internal static void LoadKeys()
{
  try
  {
    X509Certificate2 certificate = new X509Certificate2();
    lock (CompanyAuthentication.thisLock)
    {
      certificate.Import(System.Configuration.ConfigurationManager.AppSettings["companyKeyFilePath"].ToString(), System.Configuration.ConfigurationManager.AppSettings["companyKeyFilePassword"].ToString(), X509KeyStorageFlags.UserKeySet);
      CompanyAuthentication.publicKey = certificate.PublicKey.Key;
      CompanyAuthentication.privateKey = certificate.PrivateKey;
    }
  }
  catch (CryptographicException cryptoExc)
  {
    throw new InvalidOperationException("Exception creating public/private keys", cryptoExc);
  }
  catch (Exception exc)
  {
    throw new InvalidOperationException("Exception creating public/private keys", exc);
  }
}

编辑:这是功能正常的修订代码。它每次加载键文件,而不是在类构造函数中加载一次。

    SalesNetAuthentication.LoadKeys();
    using (RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)SalesNetAuthentication.publicKey)
    {
      isVerified = RSA.VerifyData(tokenData, CryptoConfig.MapNameToOID(hashType), signature);
    }

由于您有using (RSACryptoServiceProvider RSA = ...,所以当using作用域结束时,它将处理对象。

解决方案是删除using,以便在后续尝试中使用该对象,或者在每次需要使用时重新创建该对象。

问题是您正在重用CompanyAuthentication.publicKey,即使您在第一次调用时已经处理了它(将它封装在using块中会导致对其调用.Dispose()方法)。

如果你打算继续使用这个对象,我认为你不想处理它。由于它看起来是一个静态变量,你可能不想处理,直到你关闭你的应用程序。

最新更新