【问题标题】:How to limit the maximmum length of the AES Encryption Password如何限制 AES 加密密码的最大长度
【发布时间】:2020-02-07 19:11:26
【问题描述】:

我想限制加密输出代码的长度,例如 8 或 10 或 12 个字符等。

我使用“高级加密标准 (AES)”和 Cryptography.SymmetricAlgorithm.IV 创建了非常小的加密 coed。

但加密代码的结果如下:

输入密码=“090400551”

Converted Output = "mkopj3WFb6RZMp34urFLew==" // 这应该是长度的一半

我想将 8 个字符的长度减少到 12 个字符。任何 C# 密码库或算法都可以

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace AnotherEncryption
{
    class Encryption
    {

        public static class Global
        {
            // set password
            public const string strPassword = "090400551";   
            public const String strPermutation = "Secure1234";
            public const Int32 bytePermutation1 = 0x78;
            public const Int32 bytePermutation2 = 0x56;
            public const Int32 bytePermutation3 = 0x34;
            public const Int32 bytePermutation4 = 0x88;
        }

        static void Main(string[] args)
        {
            Console.Title = "Secure Password v2";
            Console.WriteLine("Output---");
            Console.WriteLine("");

            Console.WriteLine("Password:  " + Global.strPassword);

            string strEncrypted = (Encrypt(Global.strPassword));
            Console.WriteLine("Encrypted: " + strEncrypted);

            string strDecrypted = Decrypt(strEncrypted);
            Console.WriteLine("Decrypted: " + strDecrypted);

            //mkopj3WFb6RZMp34urFLew==

            Console.ReadKey();
        }

        public static string Encrypt(string strData)
        {
            byte[] test = Encoding.UTF8.GetBytes(strData);
            return Convert.ToBase64String(Encrypt(test));
        }

        public static string Decrypt(string strData)
        {
            return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(strData)));

        }

        // encrypt
        public static byte[] Encrypt(byte[] strData)
        {
            PasswordDeriveBytes passbytes =
            new PasswordDeriveBytes(Global.strPermutation,
            new byte[] { Global.bytePermutation1,
                         Global.bytePermutation2,
                         Global.bytePermutation3,
                         Global.bytePermutation4
            });

            MemoryStream memstream = new MemoryStream();
            Aes aes = new AesManaged(); 

            aes.Key = passbytes.GetBytes(aes.KeySize / 8);
            aes.IV = passbytes.GetBytes(aes.BlockSize / 8);  

            CryptoStream cryptostream = new CryptoStream(memstream, aes.CreateEncryptor(), CryptoStreamMode.Write);
            cryptostream.Write(strData, 0, strData.Length);
            cryptostream.Close();
            return memstream.ToArray();
        }

        // decrypt
        public static byte[] Decrypt(byte[] strData)
        {
            PasswordDeriveBytes passbytes =
            new PasswordDeriveBytes(Global.strPermutation,
            new byte[] { Global.bytePermutation1,
                         Global.bytePermutation2,
                         Global.bytePermutation3,
                         Global.bytePermutation4
            });

            MemoryStream memstream = new MemoryStream();
            Aes aes = new AesManaged();
            aes.Key = passbytes.GetBytes(aes.KeySize / 8);
            aes.IV = passbytes.GetBytes(aes.BlockSize / 8);

            CryptoStream cryptostream = new CryptoStream(memstream,
            aes.CreateDecryptor(), CryptoStreamMode.Write);
            cryptostream.Write(strData, 0, strData.Length);
            cryptostream.Close();
            return memstream.ToArray();
        }

    }
}

【问题讨论】:

  • 转换为 base 64 字符串使输出比输入长。
  • AES 是一种基于块的密码,块大小为 128 位或 16 字节。你不会得到不是 16 字节的倍数的输出。
  • 嗨,除 AES 之外还有其他算法或库来获取更少字符的密码吗?
  • 你为什么要加密密码?最典型的场景是您想要对密码进行哈希处理,而不是对其进行加密。
  • 您好,我需要加密密码而不是哈希。但是密码的长度很长,用户很难输入。我在 Xamarin Form(Android 移动平台)中创建。在移动设备上超过 20 个字符太长了。

标签: c# encryption cryptography aes rijndaelmanaged


【解决方案1】:

如果您将 Rijndael 设置为块大小为 8 的 CFB 模式,那么它将充当流密码 - 对于您输入的每个字节,您都会再次获得一个字节。

public static void Main(string[] args)
{
    var algorithm = new RijndaelManaged()
    {
        Mode = CipherMode.CFB,

        // This is the equivalent of BlockSize in CFB mode. We set it to 8 (bits) to prevent any buffering of data 
        // while waiting for whole blocks.
        FeedbackSize = 8,
    };

    // Don't hard-code in real life, obviously
    var key = new byte[32];
    var iv = new byte[16];

    var input = new byte[] { 1, 2, 3 };

    byte[] result;
    using (var ms = new MemoryStream())
    {
        using (var cryptoStream = new CryptoStream(ms, algorithm.CreateEncryptor(key, iv), CryptoStreamMode.Write))
        {
            cryptoStream.Write(input, 0, input.Length);
        }
        result = ms.ToArray();
    }
}

请注意,这似乎只适用于 .NET Framework - .NET Core 似乎不支持 CFB(请参阅 this GitHub issue)。


请注意,加密并不能防止篡改!人们无法阅读您的纯文本消息,但他们可以很容易地更改密文以控制它被解密的内容。流密码往往特别容易受到此影响。如果您需要阻止某人控制加密输出解密到的内容,那么您需要一个签名。

另请注意,您不应在多条消息中使用相同的 IV。创建一个随机 IV,并将其与您的消息一起传输,通常作为前 2 个字节。

【讨论】:

  • 您也忘记了存储 IV,如果没有唯一的 IV,这种加密方法会泄露数据。
  • @Maarten 我绝对没有说应该如何治疗 IV。我知道 OP 没有正确处理 IV:请随时做出自己的答案来解释这一点。我在答案的底部添加了一个简短的注释。
  • 使用 CBC(问题中使用的默认模式)但是,如果前 16 个字节相同,则只会泄漏最少的信息。使用 CFB 和相同的 IV,您几乎泄露了所有信息,即所有密码 (!)
  • FeedbackSize = 8 - 他们可能应该使用完整的块大小来提供反馈。
  • @jww 我记得如果你增加FeedbackSize,那么你的输出将是这个的倍数是否正确?也就是说,您可以获得比输入更长的输出?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
  • 1970-01-01
相关资源
最近更新 更多