便携式加密算法

时间:2013-05-10 10:36:44

标签: c# encryption

我需要实现一个新的或已经存在的加密算法,该算法使用另一个字符串作为密钥来加密和解密字符串。问题是此算法必须独立于使用它的计算机

所以方法签名是:

public static string Encrypt(this string source, string key);

public static string Decrypt(this string source, string key);

我尝试了这些算法,但它们不能按我想要的方式工作:

public static string Encrypt(this string source, string key)
{
    if (String.IsNullOrEmpty(source) || String.IsNullOrEmpty(key))
        throw new ArgumentException();

    CspParameters cspp = new CspParameters { KeyContainerName = key };

    using (var rsa = new RSACryptoServiceProvider(cspp) { PersistKeyInCsp = true })
        return BitConverter.ToString(rsa.Encrypt(UTF8Encoding.UTF8.GetBytes(source), true));
}


public static string Decrypt(this string source, string key)
{
    if (String.IsNullOrEmpty(source) || String.IsNullOrEmpty(key))
        throw new ArgumentException();

    try
    {
        CspParameters cspp = new CspParameters { KeyContainerName = key };

        using (var rsa = new RSACryptoServiceProvider(cspp) { PersistKeyInCsp = true })
        {
            string[] decryptArray = source.Split(new char[] { '-' }, StringSplitOptions.None);
            byte[] bytes = Array.ConvertAll<string, byte>(decryptArray, (s => Convert.ToByte(Byte.Parse(s, NumberStyles.HexNumber))));

            return UTF8Encoding.UTF8.GetString(rsa.Decrypt(bytes, true));
        }
    }
    catch
    { return null; }
}

我该怎么办?

1 个答案:

答案 0 :(得分:2)

KeyContainerName不是键。在上面的示例中,通过将密钥作为商店名称传递,您将在每台计算机上创建一个新的RSA密钥对,其中包含您传入密钥的商店名称(而不是像“MyRSAKeyPair”或其他任何东西的商店名称)。这意味着公钥和私钥都将完全不同,您的例程似乎无法正常工作。

另请注意:您使用的是非对称加密,这具有密钥长度的最大块大小限制。这意味着您需要创建一个分块机制(因为非对称加密很昂贵)或者使用像AES那样对称的东西,并且在每次会话的基础上使用非对称加密(例如RSA)发送AES密钥。

您需要导出RSA公钥,然后将其导入远程计算机的密钥库。更容易生成X509证书(如果您只是在两台计算机之间进行自我签名,将其公共部分导出到.CER文件中,那么您可以使用X509证书库API来获取RSA提供程序,这意味着你有一个很好的便携钥匙。

 public static RSACryptoServiceProvider GetRsaProviderFromCertificate()
 {
     X509Store store = new X509Store(StoreLocation.LocalMachine);
     store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
     X509Certificate2Collection certCollection =  (X509Certificate2Collection)store.Certificates;

     foreach(X509Certificate2 cert in certCollection)
     {
         if (cert.SubjectName.Name.IndexOf("TheCertIWantToUse") > 0)
         {
              return cert.PrivateKey as RSACryptoServiceProvider;
         }
     }

我希望这很明确......

如果你想在没有证书的情况下这样做

// Export public key (on the encrypting end)
            publicKey = rsaProvider.ToXmlString(false);
// Write public key to file
            publicKeyFile = File.CreateText(publicKeyFileName);
            publicKeyFile.Write(publicKey);   

然后在另一台机器上

            // Select target CSP
            cspParams = new CspParameters();
            cspParams.ProviderType = 1; // PROV_RSA_FULL 
            rsaProvider = new RSACryptoServiceProvider(cspParams);

            // Read public key from file
            publicKeyFile = File.OpenText(publicKeyFileName);
            publicKeyText = publicKeyFile.ReadToEnd();

            // Import public key
            rsaProvider.FromXmlString(publicKeyText);