便携式类库(PCL)Contrib - 密码学

5
我想在codeplex上的Portable Class Library Contrib项目中使用密码学,但没有找到任何关于如何使用它的文档。
我想创建一个包装类,在其中添加EncryptDecrypt方法,并且我希望这个包装类存在于可移植类库中。我已经在此项目中引用了Portable.RuntimePortable.Security.Cryptography。这样做正确吗?
然后,我想在.NET、Windows Phone和Metro项目中使用我的包装器。在这些项目中,我引用了我的包装器项目、Portable.RuntimePortable.Security.Cryptography以及相应的可移植项目,即Portable.DesktopPortable.PhonePortable.WindowsStore。这样做正确吗?
然而,当我尝试使用我的包装器类时,出现了冲突的命名空间错误。这是错误和我的包装器类:
类型 System.Security.Cryptography.AesManagedC:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client\System.Core.dllC:\Downloads\PclContrib\bin\Debug\Portable.Security.Cryptography.dll 中都存在。
public sealed class SymmetricCryptography<T> where T : SymmetricAlgorithm, new()
{
    private readonly T provider = new T();
    private readonly UTF8Encoding utf8 = new UTF8Encoding();

    private byte[] key;
    private byte[] iv;

    public byte[] Key
    {
        get { return this.key; }
    }

    public byte[] IV
    {
        get { return this.iv; }
    }

    public SymmetricCryptography()
    {
        this.key = this.provider.Key;
        this.iv = this.provider.IV;
    }

    public SymmetricCryptography(byte[] key, byte[] iv)
    {
        this.key = key;
        this.iv = iv;
    }

    public SymmetricCryptography(string password, string salt)
    {
        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, this.utf8.GetBytes(salt));
        this.key = deriveBytes.GetBytes(this.provider.KeySize >> 3);
        this.iv = deriveBytes.GetBytes(16);
    }

    public SymmetricCryptography(string password, string salt, int iterations)
    {
        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, this.utf8.GetBytes(salt), iterations);
        this.key = deriveBytes.GetBytes(this.provider.KeySize >> 3);
        this.iv = deriveBytes.GetBytes(16);
    }

    public byte[] Encrypt(byte[] input)
    {
        return this.Encrypt(input, this.key, this.iv);
    }

    public byte[] Encrypt(byte[] input, byte[] key, byte[] iv)
    {
        return this.Transform(
            input,
            this.provider.CreateEncryptor(key, iv));
    }

    public byte[] Decrypt(byte[] input)
    {
        return this.Decrypt(input, this.key, this.iv);
    }

    public byte[] Decrypt(byte[] input, byte[] key, byte[] iv)
    {
        return this.Transform(
            input,
            this.provider.CreateDecryptor(key, iv));
    }

    public string Encrypt(string text)
    {
        return this.Encrypt(text, this.key, this.iv);
    }

    public string Encrypt(string text, byte[] key, byte[] iv)
    {
        byte[] output = this.Transform(
            this.utf8.GetBytes(text),
            this.provider.CreateEncryptor(key, iv));
        return Convert.ToBase64String(output);
    }

    public string Decrypt(string text)
    {
        return this.Decrypt(text, this.key, this.iv);
    }

    public string Decrypt(string text, byte[] key, byte[] iv)
    {
        byte[] output = this.Transform(
            Convert.FromBase64String(text),
            this.provider.CreateDecryptor(key, iv));
        return this.utf8.GetString(output, 0, output.Length);
    }

    public void Encrypt(Stream input, Stream output)
    {
        this.Encrypt(input, output, this.key, this.iv);
    }

    public void Encrypt(Stream input, Stream output, byte[] key, byte[] iv)
    {
        this.TransformStream(true, ref input, ref output, key, iv);
    }

    public void Decrypt(Stream input, Stream output)
    {
        this.Decrypt(input, output, this.key, this.iv);
    }

    public void Decrypt(Stream input, Stream output, byte[] key, byte[] iv)
    {
        this.TransformStream(false, ref input, ref output, key, iv);
    }

    private byte[] Transform(
        byte[] input,
        ICryptoTransform cryptoTransform)
    {
        byte[] result;

        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (CryptoStream cryptStream = new CryptoStream(
                memoryStream,
                cryptoTransform,
                CryptoStreamMode.Write))
            {
                cryptStream.Write(input, 0, input.Length);
                cryptStream.FlushFinalBlock();
                memoryStream.Position = 0;
                result = memoryStream.ToArray();
            }
        }

        return result;
    }

    private void TransformStream(bool encrypt, ref Stream input, ref Stream output, byte[] key, byte[] iv)
    {
        // defensive argument checking
        if (input == null)
        {
            throw new ArgumentNullException("input");
        }

        if (output == null)
        {
            throw new ArgumentNullException("output");
        }

        if (!input.CanRead)
        {
            throw new ArgumentException("Unable to read from the input Stream.", "input");
        }

        if (!output.CanWrite)
        {
            throw new ArgumentException("Unable to write to the output Stream.", "output");
        }

        // make the buffer just large enough for 
        // the portion of the stream to be processed
        byte[] inputBuffer = new byte[input.Length - input.Position];
        // read the stream into the buffer
        input.Read(inputBuffer, 0, inputBuffer.Length);
        // transform the buffer
        byte[] outputBuffer = encrypt ? Encrypt(inputBuffer, key, iv)
                                        : Decrypt(inputBuffer, key, iv);
        // write the transformed buffer to our output stream 
        output.Write(outputBuffer, 0, outputBuffer.Length);
    }
}

1
如果您解决了问题,请将解决方案发布为答案,而不是将其编辑到问题中。或者您还有其他问题吗?如果是的话,您应该明确地陈述它们。 - CodesInChaos
1
顺便提一下,你的IV使用不好。每次加密时,IV应该是不同的。 - CodesInChaos
3个回答

3
文档有点欠缺,但我在FAQ中指出了这一点:

我能与我的平台特定项目共享PclContrib的类型吗? 不行,目前不行。虽然PclContrib中的类型看起来和感觉像它们的平台特定对应物,但运行时和编译器会将它们视为完全不同的类型。虽然我们有一些关于如何使其工作的想法,但这是一个我们短期内不会考虑的功能。


2
以下 .net 代码适用于桌面实现。 首先添加对Portable.Desktop和Portable.Security.Cryptography.ProtectedData的引用。
   private void button2_Click(object sender, EventArgs e)
    {
        String encrypted = PCL.CentralClass.Encrypt("yo");
        String decreypted = PCL.CentralClass.Decrypt(encrypted);
        //PCL.CentralClass.
    }
    //https://pclcontrib.codeplex.com/documentation?FocusElement=Comment
    //\Source\Portable.Security.Cryptography.ProtectedData\Security\Cryptography\ProtectedData.cs

    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }

    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }

    public static String Encrypt(String strEncrypt)
    {
        byte[] userData = GetBytes(strEncrypt);
        byte[] optionalEntropy = null;
        byte[] x = System.Security.Cryptography.ProtectedData.Protect(userData, optionalEntropy);
        return GetString(x);
    }
    public static String Decrypt(String strDecrypt)
    {
        byte[] encryptedData = GetBytes(strDecrypt);
        byte[] optionalEntropy = null;
        byte[] x = System.Security.Cryptography.ProtectedData.Unprotect(encryptedData, optionalEntropy);
        return GetString(x); ;
    }

1
原来是我的通用加密算法包装器引起了问题。PCL Contrib 包含一个名为 SymmetricAlgorithm 的类,它本身就是真正的 SymmetricAlgorithm 的包装器。如果我将我的包装器类设置为非泛型,则可以像这样工作:
public sealed class AesManagedSymmetricCryptography : SymmetricCryptography<AesManaged>
{
    #region Constructors

    public AesManagedSymmetricCryptography()
    {
    }

    public AesManagedSymmetricCryptography(byte[] key, byte[] iv)
        : base(key, iv)
    {
    }

    public AesManagedSymmetricCryptography(string password, string salt)
        : base(password, salt)
    {
    }

    public AesManagedSymmetricCryptography(string password, string salt, int iterations)
        : base(password, salt, iterations)
    {
    }

    #endregion
}

你可以在翻译的文本中加入一些使用这些函数的例子吗? - Ozgur Ozturk
我也在尝试使用pcl-contrib加密来为Windows Phone 8和Windows Store应用程序提供服务。因此,我从问题中复制了您的代码,并将其中的“sealed”删除: public class SymmetricCryptography<T> where T : SymmetricAlgorithm, new() .... 这样我就可以创建一个非泛型版本,就像您建议的那样。 您能否在某个地方发布使用此解决方案的代码? - Ozgur Ozturk
你使用了 this.provider.KeySize 但是提供程序是 SymmetricAlgorithm,并且它没有 KeySize? - Ozgur Ozturk
同时编译器找不到CryptoStream。我需要添加一个引用吗? 对于许多小问题请谅解。我只是花了太长时间让密码学运作起来... 感谢您的理解... - Ozgur Ozturk
我看到CryptoStream可用于.Net 4.5,但不适用于PCL。http://msdn.microsoft.com/en-us/library/system.security.cryptography.cryptostream.aspx如果您已经实现了自己的加密流,请分享一下吗? - Ozgur Ozturk
我在Mono实现中找到了CryptoStream: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/CryptoStream.cs 但它引用了他们System.Security.Cryptography的其他文件。 也许我应该从他们那里获取完整的库: https://github.com/mono/mono/tree/master/mcs/class/corlib/System.Security.Cryptography 这是否适用于PCL? - Ozgur Ozturk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接