2016-06-18 6 views
0

У меня есть файл сертификата .pfx на моем компьютере. Я хочу зашифровать сообщение с его открытым ключом, а затем расшифровать его с помощью private.Как шифровать, расшифровывать и подписывать с помощью сертификата .pfx?

Также я хочу подписать другое сообщение с его закрытым ключом, а затем проверить подпись. И мне нужно получить информацию о сертификате, с которым было подписано сообщение из этого сообщения.

Как это сделать, используя System.Security.Cryptography?

ответ

2

Вы можете открыть PFX в .NET, как следующее:

var path = <YOUR PFX FILE PATH>; 
var password = <YOUR PASSWORD>; 

var collection = new X509Certificate2Collection(); 

collection.Import(path, password, X509KeyStorageFlags.PersistKeySet); 

Затем перечислить через X509Certificate2Collection. Если у вас есть сертификат (при условии что один сертификат), а затем:

var certificate = collection[0]; 

Для шифрования данных, вы можете использовать:

var publicKey = certificate.PublicKey.Key as RSACryptoServiceProvider; 

var encryptedData = publicKey.Encrypt(<yourdata>, false); 

Здесь я не использовал OAEP для шифрования, но вы можете использовать его, установив fOAEP на true для второго параметра.

Для расшифровки данных, вы можете использовать:

var privateKey = certificate.PrivateKey as RSACryptoServiceProvider; 

var data = privateKey.Decrypt(encryptedData, false); 

сертификат в PFX не может иметь соответствующий закрытый ключ, так что вы можете использовать следующее свойство, чтобы проверить, если закрытый ключ существует до получения доступа к PrivateKey недвижимость

if (!certificate.HasPrivateKey) 
    throw new Exception("The certificate does not have a private key"); 

Если вы зашифровали с OAEP, то вы должны расшифровать с fOAEP набор для true.

Для регистрации данных, вы можете использовать:

var signature = privateKey.SignData(<yourdata>, "SHA1"); 

Для проверки подписи, вы можете использовать:

var isValid = publicKey.VerifyData(<yourdata>, "SHA1", signature); 

Здесь я использовал SHA1 которая не считается сильным. Вы можете использовать другие алгоритмы хеширования, такие как SHA256, которые сильнее.

И, наконец, если вы являетесь маленькой строкой, то предыдущая процедура прекрасна. Однако, если вы шифруете большие данные, я предлагаю использовать симметричное шифрование и затем шифровать симметричный ключ с помощью открытого ключа. (См. X509Certificate2 Class для полного примера)

+0

Спасибо! Но у меня также есть следующая проблема.Я подписываю сообщение с закрытым ключом сертификата. У меня также есть много других сертификатов. Я получаю подписанное сообщение, и мне нужно знать, какой открытый ключ мне нужно проверить это сообщение. Могу ли я получить эту информацию из сообщения или предоставить дополнительные данные с сообщением? – Aluminium

+0

Это зависит от формата сообщения, который у вас есть, и содержит ли он идентификатор сертификата, который его подписал. В противном случае вы должны предоставить дополнительные данные с сообщением. –

+0

Какой формат я могу использовать для передачи сообщения и идентификатора сертификата вместе? Предоставляет ли System.Security.Cryptography это? – Aluminium

0

Начиная с .NET 4.6, зависимость от * типов CryptoServiceProvider свелась:

private static byte[] SignArbitrarily(byte[] data, X509Certificate2 cert) 
{ 
    Debug.Assert(data != null); 
    Debug.Assert(cert != null); 
    Debug.Assert(cert.HasPrivateKey); 

    // .NET 4.6(.0): 
    using (RSA rsa = cert.GetRSAPrivateKey()) 
    { 
     if (rsa != null) 
     { 
      // You need to explicitly pick a hash/digest algorithm and padding for RSA, 
      // these are just some example choices. 
      return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 
     } 
    } 

    // .NET 4.6.1: 
    using (ECDsa ecdsa = cert.GetECDsaPrivateKey()) 
    { 
     if (ecdsa != null) 
     { 
      // ECDSA signatures need to explicitly choose a hash algorithm, but there 
      // are no padding choices (unlike RSA). 
      return ecdsa.SignData(data, HashAlgorithmName.SHA256); 
     } 
    } 

    // .NET 4.6.2 (currently in preview): 
    using (DSA dsa = cert.GetDSAPrivateKey()) 
    { 
     if (dsa != null) 
     { 
      // FIPS 186-1 (legacy) DSA does not have an option for the hash algorithm, 
      // SHA-1 was the only option. 
      // FIPS 186-3 (current) DSA allows any of SHA-1, SHA-2-224, SHA-2-256, 
      // SHA-2-384, and SHA-2-512 (.NET does not support SHA-2-224). 
      // KeySize < 1024 is FIPS-186-1 mode, > 1024 is 186-3, and == 1024 can 
      // be either (depending on the hardware/software provider). 
      // So, SHA-1 is being used in this example as the "most flexible", 
      // but may not currently be considered "secure". 
      return dsa.SignData(data, HashAlgorithmName.SHA1); 
     } 
    } 

    throw new InvalidOperationException("No algorithm handler"); 
} 

// Uses the same choices as SignArbitrarily. 
private static bool VerifyArbitrarily(byte[] data, byte[] signature, X509Certificate2 cert) 
{ 
    Debug.Assert(data != null); 
    Debug.Assert(signature != null); 
    Debug.Assert(cert != null); 

    using (RSA rsa = cert.GetRSAPublicKey()) 
    { 
     if (rsa != null) 
     { 
      return rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 
     } 
    } 

    using (ECDsa ecdsa = cert.GetECDsaPublicKey()) 
    { 
     if (ecdsa != null) 
     { 
      return ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256); 
     } 
    } 

    using (DSA dsa = cert.GetDSAPublicKey()) 
    { 
     if (dsa != null) 
     { 
      return dsa.VerifyData(data, signature, HashAlgorithmName.SHA1); 
     } 
    } 

    throw new InvalidOperationException("No algorithm handler"); 
} 

Для асимметричного шифрования/дешифрования, RSA является единственным алгоритмом, и требуется дополнительный режим. Новый RSAEncryptionPadding.OaepSHA1 такой же, как fOAEP: true в RSACryptoServiceProvider. Новые OAEP поддерживаются .NET, но не всеми основными поставщиками.

rsaPublic.Encrypt(data, RSAEncryptionPadding.OaepSHA1); 
rsaPrivate.Decrypt(encryptedData, RSAEncryptionPadding.OaepSHA1); 
Смежные вопросы