用RSA公钥进行的C#解密会返回垃圾字符

问题描述 投票:0回答:1

我需要使用公共密钥执行RSA解密。以下是我的代码,解密后返回垃圾值。

加密代码

public static string EncryptWithPrivate(byte[] bytes)
    {
        AsymmetricKeyParameter privatekey = null;

        using (var reader = File.OpenText(Path.Combine(Startup.Root, $"Certificates\\private.pem")))
        {
            var keypair = new PemReader(reader).ReadObject() as AsymmetricCipherKeyPair;
            privatekey = keypair.Private;
        }

        try
        {
            var engine = new Pkcs1Encoding(new RsaEngine());
            engine.Init(true, privatekey);
            var encryptedBytes = engine.ProcessBlock(bytes, 0, bytes.Length);
            if (encryptedBytes.Length > 0)
            {
                var encryptedString = Convert.ToBase64String(encryptedBytes);
                return encryptedString;
            }                              
        }
        catch (Exception ex)
        {
            ex.Log();
            return ex.Message;
        }
        return string.Empty;
    }

解密代码

public static string DecryptWithPublic(byte[] bytes)
    {
        AsymmetricKeyParameter publicKey = null;


        using (var privateKeyTextReader = new StringReader(File.ReadAllText(Path.Combine(Startup.Root, $"Certificates\\public.pem"))))
        {
            publicKey = (AsymmetricKeyParameter)new PemReader(privateKeyTextReader).ReadObject();
        }

        try
        {                              
            var decryptEngine = new Pkcs1Encoding(new RsaEngine());

            decryptEngine.Init(false, publicKey);
            return Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytes, 0, bytes.Length));
        }
        catch (Exception ex)
        {
            ex.Log();
        }
        return string.Empty;
    }

测试字符串:“ 12345678”

解密后的输出: enter image description here

我在这里做错了什么?

c# encryption rsa bouncycastle
1个回答
-1
投票

这不使用RSA,它使用AES,但如果可能会帮助您:

我被遗漏了,这需要Nuget软件包:Konscious。安全密码学DataJuggler.Core.UltimateHelper(或将TextHelper.Exists更改为!String.IsNullOrEmpty(text))。

#region using statements

using System;
using System.Text;
using System.Security.Cryptography;
using Konscious.Security.Cryptography;
using System.Linq;
using DataJuggler.UltimateHelper.Core;
using DataJuggler.Core.Cryptography.Objects;

#endregion

namespace DataJuggler.Core.Cryptography
{

    #region class CryptographyHelper
    /// <summary>
    /// This object hands all encryption for this application.
    /// </summary>
    public class CryptographyHelper
    {

        #region Private Variables
        // We can use a fixed pepper for the PBKDF2 salt.
        private static byte[] _pepper = new byte[] { 0x04, 0xC5, 0x02, 0xF8, 0xD3, 0xD4, 0x23, 0xB9 };
        public const string DefaultPassword = "NotASecret";
        #endregion

        #region Methods

            #region CreateSalt()
            /// <summary>
            /// This method creates a byte array to use
            /// </summary>
            /// <returns></returns>
            private static byte[] CreateSalt()
            {
                // initial value
                byte[] buffer = null;

                // Create a strong random number generator
                using (var rng = new RNGCryptoServiceProvider())
                {
                    buffer = new byte[16];
                    rng.GetBytes(buffer);
                }

                // return value
                return buffer;
            }
            #endregion

            #region DecryptString(string  stringToDecrypt, string password)
            /// <summary>
            /// Decrypts a string passed in.
            /// </summary>
            /// <param customerName="stringToDecrypt">String that needs to be deciphered.</param>
            /// <param customerName="ProductPassword">Code to unlock this productPassword.</param>
            /// <returns></returns>
            public static string DecryptString(string stringToDecrypt, string password)
            {
                // initial value
                string decryptedValue = "";

                try
                {
                    // if both strings exist
                    if (TextHelper.Exists(stringToDecrypt, password))
                    {
                        var ivAndCiphertext = Convert.FromBase64String(stringToDecrypt);
                        if (ivAndCiphertext.Length >= 16)
                        {
                            var iv = new byte[16];
                            var ciphertext = new byte[ivAndCiphertext.Length - 16];
                            Array.Copy(ivAndCiphertext, 0, iv, 0, iv.Length);
                            Array.Copy(ivAndCiphertext, iv.Length, ciphertext, 0, ciphertext.Length);

                            using (var aes = AesManaged.Create())
                            using (var pbkdf2 = new Rfc2898DeriveBytes(password, _pepper, 32767))
                            {
                                var key = pbkdf2.GetBytes(32);

                                aes.Mode = CipherMode.CBC;
                                aes.Padding = PaddingMode.PKCS7;
                                aes.Key = key;
                                aes.IV = iv;

                                // create a new Decryptor                            
                                using (var aesTransformer = aes.CreateDecryptor())
                                {
                                    // get a byte array of the plain text
                                    var plaintext = aesTransformer.TransformFinalBlock(ciphertext, 0, ciphertext.Length);

                                    // set the return value
                                    decryptedValue = Encoding.UTF8.GetString(plaintext);
                                }
                            }
                        }
                    }
                }
                catch
                {
                }

                // return value
                return decryptedValue;
            }
            #endregion

            #region DecryptString(string stringToDecrypt)
            /// <summary>
            /// This method decrypts a string using the default password.
            /// </summary>
            /// <param name="stringToDecrypt"></param>
            /// <returns></returns>
            public static string DecryptString(string stringToDecrypt)
            {
                // return value
                return DecryptString(stringToDecrypt, DefaultPassword);
            }
            #endregion

            #region EncryptString(string  stringToEncrypt, string password)
            /// <summary>
            /// Encrypts a strings passed in using CBC mode and a moderately decent KDF.  Does not provide integrity.
            /// This method will return a different value every time called, yet will still decrypt correctly.
            /// </summary>
            /// <param customerName="stringToEncrypt">String to encrypt</param>
            /// <param customerName="productPassword">productPassword needed to unlock encrypted string</param>
            /// <returns>A new string that must have the same productPassword passed in to unlock.</returns>
            public static string EncryptString(string stringToEncrypt, string password)
            {
                // initial value
                string encryptedString = "";

                try
                {
                    // if both strings exist
                    if (TextHelper.Exists(stringToEncrypt, password))
                    {
                        // Remember to dispose of types that implement IDisposable - this old code had lots of memory leaks.
                        using (var aes = AesManaged.Create())
                        using (var pbkdf2 = new Rfc2898DeriveBytes(password, _pepper, 32767)) // MD5 is insecure as KDF, we use PBKDF2 instead.
                        using (var rng = new RNGCryptoServiceProvider())
                        {
                            var key = pbkdf2.GetBytes(32); // Let's use AES-256.
                            var iv = new byte[16];
                            rng.GetBytes(iv); // We always create a new, random IV for each operation.

                            var plaintext = Encoding.UTF8.GetBytes(stringToEncrypt); // We use UTF8

                            aes.Mode = CipherMode.CBC;
                            aes.Padding = PaddingMode.PKCS7;
                            aes.Key = key;
                            aes.IV = iv;

                            using (var aesTransformer = aes.CreateEncryptor())
                            {
                                var ciphertext = aesTransformer.TransformFinalBlock(plaintext, 0, plaintext.Length);
                                var ivAndCiphertext = new byte[iv.Length + ciphertext.Length];
                                Array.Copy(iv, 0, ivAndCiphertext, 0, iv.Length);
                                Array.Copy(ciphertext, 0, ivAndCiphertext, iv.Length, ciphertext.Length);
                                encryptedString = Convert.ToBase64String(ivAndCiphertext);
                            }
                        }
                    }
                }
                catch
                {
                }

                // return value
                return encryptedString;
            }
            #endregion

            #region EncryptString(string stringToEncrypt)
            /// <summary>
            /// Override that uses default password
            /// </summary>
            /// <param name="stringToEncrypt"></param>
            /// <returns></returns>
            public static string EncryptString(string stringToEncrypt)
            {
                return EncryptString(stringToEncrypt, DefaultPassword);
            }
            #endregion

            #region GeneratePasswordHash(string password, int verifyRetries = 0)
            /// <summary>
            /// This method hashes the password using Konscious.Security.Cryptography's implementation of Argon2.
            /// The salt is returned with the password separated by 4 | (pipe characters I think is the name).
            /// You can decrypt from the encrypted password hash to determine the passwordhash and salt, but you cannot decrypt from 
            /// password hash back to the password.
            /// This method uses the default password, which is NotASecret.
            /// </summary>
            /// <param name="password">The password to create a hash for</param>
            /// <param name="verifyRetries">If verify retries is above 0, this method will attempt to verify
            /// the generated password hash with the same credentials. If it can't be verified, it will retry
            /// up until this value for retries count. The value must be between 0 and 3. After 3 it fails.</param>
            /// <returns></returns>
            public static string GeneratePasswordHash(string password, int verifyRetries = 0)
            {
                // call the override
                return GeneratePasswordHash(password, DefaultPassword, verifyRetries);
            }
            #endregion

            #region GeneratePasswordHash(string password, string keyCode, int verifyRetries = 0)
            /// <summary>
            /// This method hashes the password using Konscious.Security.Cryptography's implementation of Argon2.
            /// The salt is returned with the password separated by 4 | (pipe characters I think is the name).
            /// You can decrypt from the encrypted password hash to determine the passwordhash and salt, but you cannot decrypt from 
            /// password hash back to the password.
            /// </summary>
            /// <param name="password">The password to create a hash for</param>
            /// <param name="keyCode">A keycode string you create that is used to encrypt/decrypt the password hash 
            /// after it is created. You can decrypt from the encrypted password hash to determine the passwordhash and salt, but you cannot decrypt from 
            /// password hash back to the password.
            /// </param>
            /// <param name="verifyRetries">If verify retries is above 0, this method will attempt to verify
            /// the generated password hash with the same credentials. If it can't be verified, it will retry
            /// up until this value for retries count. The value must be between 0 and 3. After 3 it fails.</param>
            /// <returns></returns>
            public static string GeneratePasswordHash(string password, string keyCode, int verifyRetries = 0)
            {
                // get the passwordHash
                string passwordHash = null;

                // local
                bool verified = false;

                // if the password exists
                if (TextHelper.Exists(password, keyCode))
                {
                    // get the passwordHash
                    passwordHash = HashPart1(password, keyCode);

                    // it will only try up to 3 times, then it bails
                    if ((verifyRetries > 0) && (verifyRetries <= 3))
                    {
                        // try up to 3 times if verifyRetries is set to 3
                        for (int x = 0; x < verifyRetries; x++)
                        {
                            // if all 3 strings exist
                            if (TextHelper.Exists(password, password, keyCode))
                            {
                                // does 
                                verified = VerifyHash(password, keyCode, passwordHash);
                            }

                            // if the value for verified is true
                            if (verified)
                            {
                                // break out of the loop
                                break;
                            }

                            // get the passwordHash (again)
                            passwordHash = HashPart1(password, keyCode);
                        }

                        // if not veriified
                        if (!verified)
                        {
                            // password hash could not be created
                            passwordHash = "";
                        }
                    }
                }

                // return value
                return passwordHash;
            }
            #endregion

            #region HashPart1(string password, string keyCode)
            /// <summary>
            /// This method is used to call some portions of the GeneratePasswordHash
            /// multiple times.
            /// </summary>
            /// <param name="part1"></param>
            /// <param name="keyCode"></param>
            /// <returns></returns>
            private static string HashPart1(string password, string keyCode)
            {
                // initial value
                string part1 = "";

                try
                {
                     // Update 1.0.9 create the salt every time as the salt might be the problem (?)
                     byte[] salt = CreateSalt();

                    // get the byte array
                    byte[] passwordBits = HashPassword(password, salt);

                    // create the hashInfo
                    PasswordHashInfo hashInfo = new PasswordHashInfo(passwordBits, salt);

                    // get the hashInfo
                    string partI = hashInfo.ToString();

                    // set the return value
                    part1 = EncryptString(partI, keyCode);
                }
                catch (Exception error)
                {
                    // for debugging only for now, I may return a response one day
                    DebugHelper.WriteDebugError("HashPart1", "CryptographyHelper", error);

                    // explicit set to null
                    part1 = "";
                }

                // return value
                return part1;
            }
            #endregion

            #region HashPassword(string password, byte[] salt)
            /// <summary>
            /// Hash this password
            /// </summary>
            /// <param name="password"></param>
            /// <param name="keyCode"></param>
            /// <param name="salt"></param>
            /// <returns></returns>
            private static byte[] HashPassword(string password, byte[] salt)
            {
                // initial value
                byte[] hash = null;

                // if all 3 strings exist
                if (TextHelper.Exists(password))
                {
                    // Create a new instance of an 'Argon2id' object.
                    var argon2 = new Argon2id(Encoding.Unicode.GetBytes(password));

                    argon2.Salt = salt;
                    argon2.DegreeOfParallelism = 8; // four cores
                    argon2.Iterations = 2;
                    argon2.MemorySize = 1024 * 1024; // 1 GB

                    // get the hash
                    hash = argon2.GetBytes(16);
                }

                // return value
                return hash;
            }
            #endregion

            #region VerifyHash(string userTypedPassword, string storedPasswordHash)
            /// <summary>
            /// This method is used to verify the Hash created is the same as a hash stored in the database.
            /// This method uses the default password, which is NotASecret. If you stored the password with a keycode
            /// you must use that keycode to decrypt and if you used the default value to encrypt you must use the default
            /// password to decrypt.
            /// </summary>
            /// <param name="userTypedPassword">The password typed in by a user for a login attempt.</param>
            /// <param name="storedPasswordHash">The password hash that is stored with the salt.</param>
            /// <returns></returns>
            public static bool VerifyHash(string userTypedPassword, string storedPasswordHash)
            {
                return VerifyHash(userTypedPassword, DefaultPassword, storedPasswordHash);
            }
            #endregion

            #region VerifyHash(string userTypedPassword, string keyCode, string storedPasswordHash)
            /// <summary>
            /// This method is used to verify the Hash created is the same as a hash stored in the database.
            /// </summary>
            /// <param name="password"></param>
            /// <param name="keyCode"></param>
            /// <param name="salt"></param>
            /// <returns></returns>
            public static bool VerifyHash(string userTypedPassword, string keyCode, string storedPasswordHash)
            {
                // initial value
                bool verified = false;

                try
                {
                    // locals
                    // get the password up until the separator
                    string password = "";
                    string salty = "";
                    byte[] salt = null;
                    byte[] storedHash = null;

                    // if all the parameters exist
                    if (TextHelper.Exists(userTypedPassword, keyCode, storedPasswordHash))
                    {
                        // we must first decrypt the storedPasswordHash with the keycode
                        string decryptedHash = DecryptString(storedPasswordHash, keyCode);

                        // if the decryptedHash exists
                        if (TextHelper.Exists(decryptedHash))
                        {
                            // get the index of the 4 pipe characters
                            int index = decryptedHash.IndexOf("||||");

                            // if the index was found
                            if (index >= 0)
                            {
                                // get the password
                                password = decryptedHash.Substring(0, index);
                                salty = decryptedHash.Substring(index + 4);
                                salt = Encoding.Unicode.GetBytes(salty);
                                storedHash = Encoding.Unicode.GetBytes(password);
                            }

                            // now verify with the override
                            verified = VerifyHash(userTypedPassword, salt, storedHash);
                        }
                    }
                }
                catch 
                {

                }

                // return value
                return verified;
            }
            #endregion

            #region VerifyHash(string password, byte[] salt, byte[] storedHash)
            /// <summary>
            /// This method is used to verify the Hash created is the same as the 
            /// </summary>
            /// <param name="password"></param>
            /// <param name="keyCode"></param>
            /// <param name="salt"></param>
            /// <param name="newHash"></param>
            /// <returns></returns>
            public static bool VerifyHash(string password, byte[] salt, byte[] storedHash)
            {
                // initial value
                bool verified = false;

                // if all the parameters exist
                if (TextHelper.Exists(password) && (salt.Length > 0) && (storedHash.Length > 0))
                {
                    // generate the loginHash again
                    var newHash = HashPassword(password,  salt);

                    // set the return value
                    verified = storedHash.SequenceEqual(newHash);
                }

                // return value
                return verified;
            }
            #endregion

        #endregion

    }
    #endregion

}

我的Nuget软件包的这一部分:DataJuggler.Core.Cryptography(Dot Net Core 3.1)DataJuggler.Core.UltimateHelper(点网框架)

或者项目在我的Git Hub主页上:github.com/DataJuggler

[我刚刚发布了有关密码哈希和加密以及该项目的新动画视频,如果有人想观看:https://youtu.be/w4NrmpeHykE

也许这会帮到您,几周前有人帮助了我。

© www.soinside.com 2019 - 2024. All rights reserved.