C--密码学高级教程-七-

80 阅读32分钟

C# 密码学高级教程(七)

原文:Pro Cryptography and Cryptanalysis

协议:CC BY-NC-SA 4.0

二十一、整数密码分析

整数密码分析代表了一种特殊的密码分析攻击,它适用于基于替换置换网络构建的分组密码。该攻击由 Lars Knudsen 设计为针对 Square [1 ]的专用攻击,因此被称为 Square 攻击。

置换网络代表了分组密码最重要的弱点之一。一旦网络可以被发现(让我们直观地说),那么对分组密码的攻击可以毁灭性地破坏整个密码系统。下一个易受攻击的点是密钥和用于置换密钥的表。一旦密钥接近真实的或相同的,那么我们就接近破解密码系统。这种密钥的一个例子是

        private byte[]PermutationTableForKey = {
            06, 30, 13, 07, 05, 35, 15, 14,
            12, 18, 03, 38, 09, 10, 22, 25,
            16, 04, 21, 08, 39, 37, 36, 02,
            24, 11, 28, 27, 29, 23, 33, 01,
            32, 17, 31, 00, 26, 34, 20, 19
        };

在接下来的几页中,我们将介绍实现分组密码所需的必要元素,并确定为了发起整体密码分析攻击而必须关注的元素,例如构建 Feistel 网络(参见清单 22-2 )和为密钥生成置换表(清单 22-4 )。一旦对这两个阶段有了清楚的理解,如何进行完整的密码分析就变得非常清楚了。

基本概念

为了实现和设计完整的密码分析攻击,首先理解基本概念是非常重要的。所以让我们把下面的概念作为主要的出发点。在此基础上,我们将设计和实施这样的攻击,目的只是为了教育。

让我们考虑( G ,+)是一个有限阿贝尔群或序 k 。下面的产品组,Gn=G×…×G,是具有形式为v=(v1,…, v n 的元素的组,其中 v i G n 内的加法被定义为组件方式。所以现在我们有u*+v=w持有为 uvwGnuI+v*

我们用 B 表示向量的多重集。在 B 上定义的积分代表所有矢量的和, S 。换句话说,积分被定义为\int S=\sum \limits_{v\in B}v,求和运算被定义为 G * n * 的分组运算。

当设计整数密码分析攻击时,知道并计算明文和密文中的字数是非常重要的。对于我们的例子,这个数字将用 n 来表示。另一个需要注意的非常重要的数字是明文和密文的数量,用 m 表示。通常, m = k (即 k = | G |),代表明文和密文的向量 vB ,以及G=GF(2BG=

前进到攻击,其中一方将试图在特定数量的加密轮次之后预测位于积分中的值。基于这一目的,区分以下三种情况是有益的:(1)在所有字都相等的情况下(例如 i ),(2)所有字都不同,(3)求和到预先预测的某个值。

让我们考虑将bgn声明为和以前一样的固定索引 i 。发生了以下三种情况:

  1. vI=c,对于所有 vB

  2. {v【I】:【v】**【b】} =

** \sum \limits_{v\in B}{v}_i={c}^{\prime }

 *

其中 ccG*是一些事先已知并固定的值。

下面的例子代表了一种典型的情况,其中 m = k ,在 B 中找到的向量的数量等于所考虑的组中的元素的数量。通过使用拉格朗日定理,我们可以看到是否所有的字, i th 都相等,然后很清楚来自积分的Ith字将取来自 G 的中性元素的值。

以下两个定理是必要的,并且对于任何想要将整数密码分析转化为实践的实际开发者来说是必须的。

定理 21-1【1,定理 1,第 114 页】**。**让我们考虑( G ,+) a 有限阿贝尔加群。阶为 1 或 2 的元素的子组表示为L= {GG:G+G= 0 }。我们认为写作 s ( G )是在 G 中找到的所有元素的总和\sum \limits_{g\in G}g。接下来我们考虑s(G)=∑HHH。更多的,理解下面这个类比很重要:s(G)∈H,即s(G)+s(G)= 0。

也就是说,对于G=GF(2B)我们得到 s ( G ) = 0,对于 Z / mZ 我们得到s(Z/mZ)=m/2 当我们也有书面群的乘法情况(见定理 21-2)。

由此 21-2【1,定理 2,第 114 页】。让我们考虑( G ,∫)一个有限阿贝尔乘法群。1 阶或 2 阶元素的子群表示为H= {GG:GG= 1 }。我们认为写作 p ( G )是 G 所有元素的乘积\prod \limits_{g\in G\ }g。接下来,我们考虑p(G)=\prod \limits_{h\in H}h。更多,理解下面这个类比很重要:p(G)∈H,即p(G)∫p(G)= 1。

举个例子,如果我们有G=(Z/pZ)其中 p 是质数, p ( G )是 1,p(G)= 1。这是用威尔逊定理证明的。

实用方法

这一节将展示如何使用?NET 框架和 C# 编程语言。下面的方法代表了一个 Feistel 网络在 C# 中的基本实现,可以覆盖当前的块大小。我们将使用重复的序列,目的是创造一个弱点,以显示它如何被利用和制造攻击。

清单 21-1 展示了如何构建和设计整体密码分析攻击。清单 21-2 展示了 Feistel 网络是如何构建的。一旦我们有了结构,要成功攻击,重要的是要“弄清楚”Feistel 网络是如何构建的,并创建一个它的副本或至少是与原始网络相似的东西。清单 21-3 展示了如何实现块数据,清单 21-4 展示了如何生成密钥。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace IntegralCryptanalysis
{
    public class Key
    {
        //** permutation table (initial)
        //** used to permutate the key
        private byte[] initial_permutation_table_1 = {
            06, 30, 13, 07, 05, 35, 15, 14,
            12, 18, 03, 38, 09, 10, 22, 25,
            16, 04, 21, 08, 39, 37, 36, 02,
            24, 11, 28, 27, 29, 23, 33, 01,
            32, 17, 31, 00, 26, 34, 20, 19
        };

        /// <summary>
        /// The representation of the key as a byte array
        /// </summary>
        public byte[] KeyBytes
        {
            get; set;
        }

        /// <summary>
        /// Encryption and decryption key for a text
        /// </summary>
        /// <param name="keyAsAString">The key to use for this instance</param>
        public Key(string keyAsAString)
        {
            int k = 0, key_length = keyAsAString.Length;

            //** expansion of the key to a maximum of 40 bytes
            while (keyAsAString.Length < 40)
                keyAsAString += keyAsAString[k++];

            KeyBytes = System.Text.Encoding.UTF8.GetBytes(keyAsAString);

            //** permutation of the key bytes using
            //** initial_permutation_table_1
            for (k = 0; k < KeyBytes.Length; k++)
                KeyBytes[k] = KeyBytes[initial_permutation_table_1[k]];

            Debug.WriteLine("The post permutation key is: "+ System.Text.Encoding.UTF8.GetString(KeyBytes));
        }

        /// <summary>
        /// Generate the keys that are used within the round function
        /// </summary>
        /// <returns>A list with the keys that are of 64-bit. The format is ulong.</returns>
        public List<ulong> ReturnRoundKeys()
        {
            //** Rounds is defined as 64-bit
            //** keys found in the Key string
            int count_of_round = KeyBytes.Length / 8;
            List<ulong> round_keys = new List<ulong>();

            for (int k = 0; k < count_of_round; k++)
            {
                byte[] round_key_bytes = new byte[8];
                ulong round_key = 0;

                Array.Copy(KeyBytes, k * 8, round_key_bytes, 0, 8);
                Array.Reverse(round_key_bytes);

                round_key = BitConverter.ToUInt64(round_key_bytes, 0);

                round_keys.Add(round_key);
            }
            return round_keys;
        }
    }
}

Listing 21-4The Key Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IntegralCryptanalysis
{
    public class Block
    {
        /// <summary>
        /// Represents the data that are held by the block
        /// </summary>
        public byte[] DataStructure { get; set; }

        /// <summary>
        /// Represents the left half of the data block
        /// </summary>
        public byte[] LeftHalf
        {
            get
            {
                return DataStructure.Take(DataStructure.Length / 2).ToArray();
            }
            set
            {
                Array.Copy(value, DataStructure, DataStructure.Length / 2);
            }
        }

        /// <summary>
        /// Represents the right half of the data block
        /// </summary>
        public byte[] RightHalf
        {
            get
            {
                return DataStructure.Skip(DataStructure.Length / 2).ToArray();
            }
            set
            {
                Array.Copy(value, 0, DataStructure, DataStructure.Length / 2, DataStructure.Length / 2);
            }
        }

        /// <summary>
        /// Get and return as BitArray the left half of the block data
        /// </summary>
        public BitArray TheLeftBitsOfBlock
        {
            get
            {
                return new BitArray(LeftHalf);
            }
        }

        /// <summary>
        /// Get and return as BitArray the right half of the block data
        /// </summary>
        public BitArray RightBitsOfBlock
        {
            get
            {
                return new BitArray(RightHalf);
            }
        }

        /// <summary>
        /// Representation of the size in bytes of the Block
        /// </summary>
        public int BlockSize
        {
            get
            {
                return DataStructure.Length;
            }
        }

        /// <summary>
        /// The representation of a data block. Constructor
        /// </summary>
        /// <param name="size_of_the_block">The size value (in bytes) of the block</param>
        public Block(int size_of_the_block)
        {
            DataStructure = new byte[size_of_the_block];
        }

        /// <summary>
        /// The representation of a data block. Constructor
        /// </summary>
        /// <param name="the_data_block">the data content stored by the block</param>
        public Block(byte[] the_data_block)
        {
            DataStructure = the_data_block;
        }

        /// <summary>
        /// Swaps the halves (left and right) of the block
        /// </summary>
        public void SwapHalfes()
        {
            byte[] temporary = LeftHalf;
            LeftHalf = RightHalf;
            RightHalf = temporary;
        }

        /// <summary>
        /// Converts the Block to a UTF-8 string
        /// </summary>
        /// <returns>String representation of this block</returns>
        public override string ToString()
        {
            return System.Text.Encoding.UTF8.GetString(DataStructure);
        }
    }

}

Listing 21-3Implementing the Block Data

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IntegralCryptanalysis
{
    public class FeistelNetwork
    {
        //** represents the size in bytes
        //** for each of the block
        public int BlockSize
        {
            get;
            private set;
        }

        //** the password code for
        //** encryption and decryption
        public string PasswordCode
        {
            get;
            set;
        }

        /// <summary>
        /// The basic constructor of Feistel Class.
        /// </summary>
        /// <param name="password_code">represents the
        /// password code</param>
        public FeistelNetwork(string password_code)
        {
            this.PasswordCode = password_code;
            this.BlockSize = 16;
        }

        /// <summary>
        /// Constructs a new instance of the Feist class, with a custom blocksize
        /// </summary>
        /// <param name="password_code">Passcode used in this instance</param>
        /// <param name="the_block_size">Size of the blocks to use in this instance</param>
        public FeistelNetwork(string password_code, int the_block_size) : this(password_code)
        {
            this.BlockSize = the_block_size;
        }

        /// <summary>
        /// Encryption operation of the clear text using the password code
        /// </summary>
        /// <param name="clearText">The string to encrypt</param>
        /// <returns>The encrypted text.</returns>
        public string EncryptionOp(string clearText)
        {
            return DoCiphering(clearText, true);
        }

        /// <summary>

        /// Decryption operation of the encrypted text using the password code
        /// </summary>
        /// <param name="clearText">The string to decrypt</param>
        /// <returns>The decrypted text.</returns>
        public string DecryptionOp(string clearText)
        {
            return DoCiphering(clearText, false);
        }

        /// <summary>
        /// Do a Feistel encryption on the text
        /// </summary>
        /// <param name="sourceText">The clear text or encrypted text to encrypt/decrypt</param>
        /// <param name="isClearText">Decide if the given text represents (true) or not (false) a plaintext string</param>
        /// <returns>A string of plain or ciphered
        /// text</returns>
        private string DoCiphering(string sourceText, bool isClearText)
        {
            int pointer_block = 0;
            string cipher_text_posting = "";
            List<ulong> the_round_keys = new Key(PasswordCode).ReturnRoundKeys();

            //** Do a padding operation to
            //** the string using '\0'.
            //** The output will
            //** be a multiple of <blocksize>
            while (sourceText.Length % BlockSize != 0)
                sourceText += new char();

            //** in case of decryption, reverse

            //** the encryption keys
            if (!isClearText)
                the_round_keys.Reverse();

            byte[] the_text_bytes = Encoding.UTF8.GetBytes(sourceText);

            //** do iteration through the text
            //** moving with <blocksize> bytes per iteration
            while (pointer_block < the_text_bytes.Length)
            {
                byte[] the_block_as_bytes = new byte[BlockSize];
                Array.Copy(the_text_bytes, pointer_block, the_block_as_bytes, 0, BlockSize);

                Block text_as_block = new Block(the_block_as_bytes);

                //** if we have a ciphertext,
                //** swap it in halves
                if (!isClearText)
                    text_as_block.SwapHalfes();

                //** each round keys will be
                //** applied to the text
                foreach (ulong the_round_key in the_round_keys)
                    text_as_block = RoundOnTheBlock(text_as_block, the_round_key);

                //** build the output by appending it
                if (!isClearText) text_as_block.SwapHalfes();
                cipher_text_posting += text_as_block.ToString();

                pointer_block += BlockSize;
            }
            return cipher_text_posting.Trim('\0');
        }

        /// <summary>
        /// Do a single round encryption on the block
        /// </summary>
        /// <param name="theBlock">The block that will be encrypted or decrypted</param>
        /// <param name="theRoundKey">The round key which will be applied as the round function</param>
        /// <returns>The next block in the round sequence</returns>
        private Block RoundOnTheBlock(Block block, ulong theRoundKey)
        {
            ulong theRoundFunction = 0;

            Block roundBlock = new Block(block.BlockSize);

            BitArray keyBits = new BitArray(BitConverter.GetBytes(theRoundKey)), funcBits = block.RightBitsOfBlock.Xor(keyBits);

            roundBlock.LeftHalf = block.RightHalf;

            //** do the proper casting AND round
            //** the function bits to an int
            //** set R(i+1) as L(i) XOR f
            theRoundFunction = ToInteger64(funcBits);
            roundBlock.RightHalf = BitConverter.GetBytes(ToInteger64(block.TheLeftBitsOfBlock) ^ theRoundFunction);

            return roundBlock;
        }

        /// <summary>
        /// Helper method used for conversion of BitArray to have an integer representation
        /// </summary>
        /// <param name="theArray">BitArray that will be converted</param>
        /// <returns>A value of 64-bit integer of the array</returns>
        private ulong ToInteger64(BitArray theArray)
        {
            byte[] array_as_byte = new byte[8];
            theArray.CopyTo(array_as_byte, 0);
            return BitConverter.ToUInt64(array_as_byte, 0);
        }
    }

}

Listing 21-2Building the Feistel Network

using System;
using System.IO;

namespace BuildingIntegralCryptanalysis
{
    class Program
    {
        static void Main(string[] args)
        {
            string theKeyword = "", data_input = "",
                   data_output = "", data_file = "";

            FeistelNetwork feist_network;
            StreamReader file_stream_reader;
            StreamWriter file_stream_writer;

            //** create a help text for the user
            const string helperData =
            @"Building Integral Cryptanalysis Attack
              Usage:
               private [-option] keyword
                         input_file output_file
                          Options:
                             -enc Encrypt the file passed as
                                          input using the keyword
                             -dec Decrypt the file passed as
                                          input using the keyword";

            //** show in the console the helper
            //** if we have less than four arguments
            if(args.Length < 4)

            {
                Console.WriteLine(helperData);
                return;
            }
            else if(args[1].Length < 10 ||
                                              args[1].Length > 40)
            {
                 //** Output usage if the password
                 //** is too short/long
                 Console.Write("The length of the password is
                 invalid. The password should have between 10-40 characters.\n" + helperData);

                 return;
            }

            theKeyword = args[1];
            data_input   = args[2];
            data_output  = args[3];

            //** environment input/output configuration
            feist_network = new FeistelNetwork(theKeyword);
            file_stream_reader = new StreamReader(data_input);
            file_stream_writer = new
                                     StreamWriter(data_output);

            //** Read the data from the input file
            data_file = file_stream_reader.ReadToEnd();
            file_stream_reader.Close();

            if (args[0] == "-enc")
            {
                //** do the encryption based
                //** on the argument provided
                string ciphertext =
                                   feist_network.EncryptionOp(data_file);
                file_stream_writer.Write(ciphertext);
                Console.WriteLine("The file has been encrypted
                        with success. The file has been saved
                                               to: " + data_output);
            }
            else if(args[0] == "-dec")

            {
                //** do the decryption based on the argument
                string thePlaintext =
                                   feist_network.DecryptionOp(data_file);
                file_stream_writer.Write(thePlaintext);
                Console.WriteLine("The file has been decrypted
                             with success. The file has been saved
                             to: " + data_output);
            }
            else
            {
                //** invalid option selected
                Console.Write("The selected option is invalid.
                               Please, choose another option.\n"
                               + helperData);
            }

            file_stream_writer.Close();

            Console.ReadKey();
        }
    }
}

Listing 21-1The Main Program

结论

在这一章中,我们讨论了整体密码分析以及这种攻击是如何设计和实现的。我们提出了一种建立分组密码系统的方法,并结合脆弱点来说明如何应用整数密码分析攻击。

在本章结束时,您现在可以

  • 设计并实现一个简单的分组密码

  • 理解这种密码的两个弱点,例如 Feistel 网络和生成置换表来置换密钥

  • 了解 Feistel 网络是如何实现的

  • 使用排列表,并在密钥上使用它们

文献学

  1. 琼·代蒙、拉斯·努森和文森特·里门,《分组密码方阵》。快速软件加密(FSE) 1997,“计算机科学讲义*第 1267 卷(第 149–165 页)。以色列海法:施普林格出版社。citeserx 10 . 1 . 1 . 55 . 6109。1997.**

二十二、攻击

在这一章中,我们将分析分布式环境中可能发生的最重要的攻击(云计算 [3 或大数据),以及如何使用具有 8.0 版本功能的 C# 编程语言 [2 来利用它们。作为参考,我们将使用一个 ASP.NET MVC 5(也适用于以前版本的 MVC,比如 1.0、2.0、3.0 和 4.0)应用作为例子,它使用 C# 作为后端编程语言。

web 应用上每天发生的三种最常见的攻击是重定向攻击、SQL 注入和跨站脚本(XSS)。

这里描述的方法是道德黑客领域的一部分,错误地使用它们会给企业带来重大灾难。这些方法对红队队员非常有用,其中一些方法将用于后期开发。

端口转发和如何防止开放重定向攻击

通过端口转发,黑客无法访问您,但是可以利用路由器在 web 端口上进行配置。

通过将用户重定向到外部恶意 URL,重定向到使用基于 querystring 的请求指定的 URL 的 web 应用很容易被篡改。这种攻击被称为开放重定向攻击

要执行攻击并应对此漏洞,了解登录重定向在 ASP.NET MVC web 应用项目中的工作方式非常重要。在下面的例子中,我们可以看到,如果我们要访问一个结构中有[Authorize]属性的控制器动作,这将把未授权的用户重定向到/Account/LogOn视图。提到的到/Account/LogOn的重定向在其结构中有一个称为returning_url querystring的参数,这样用户在成功登录后将被返回到所请求的真正的 URL。

基于开放重定向的攻击是非常危险的。攻击者确切地知道我们何时开始登录某个网站。这可能使我们容易受到网络钓鱼攻击。例如,考虑一个攻击者,他向订阅了某个网站的用户发送恶意电子邮件,以获取他们的密码。

让我们考虑以下示例,其中攻击者向用户发送包含特定网页(例如 http://apressprocryptoexample.com )上的登录页面的链接,该链接在其组件中具有到伪造页面的重定向,

http://apressprocryptoexample.com/Account/LogOn?returnUrl=http://apresprocryptoexample.com/Account/LogOn 。注意返回的 URL,它指向 apresprocryptoexample.com. Note that,单词“apress”中少了一个"s"这意味着域名apresprocryptoexample.com正在被黑客控制。

如果登录正确,来自 ASP.NET MVC 的AccountController LogOn动作将把我们重定向到 querystring 参数中提到的 URL,returning_url。在这种情况下,该 URL 就是攻击者使用的 URL,即 http://apresprocryptoexample.com 。如果我们不注意,我们不会注意到浏览器的不同。攻击者是一个非常精通此道的人,他会小心翼翼地确保伪造的页面看起来与原始页面一模一样。假登录页面包含一条错误消息,提示我们需要使用我们的凭据再次登录。一旦我们重新输入我们的凭证,假登录页面将保存数据并把我们送回原来的页面,ApressProCryptoExample.com。在这一点上,ApressProCryptoExample.com已经成功地让我们登录了,这个假的认证页面能够把我们重定向到那个特定的页面。最终的结果是基于这样一个事实,即攻击者知道我们的凭证(用户名和密码),而我们,真正的用户,不知道我们已经如此容易地提供了我们的凭证 [4 ]。

让我们继续来看看我们的应用中的LoginAuthentication动作的代码(清单 22-1 )。我们定义的控制器将返回一个到returning_url的重定向。对于returning_url参数,完全没有验证。

表 22-1

SQL 注入的其他示例

|

SQL 注入的例子

|

描述

| | --- | --- | | ' or '' | 字符串字符作为指示符 | | -- or # | 单行注释 | | /*..*/ | 多行注释 | | + | 添加、连接(也适用于 URL) | | &#124;&#124; | 双重连接 | | % | 通配符属性指示器 | | ?Param1=foo&Param2=bar | URL 参数 | | PRINT | 非事务命令 | | @variable | 局部变量 | | @@variable | 全局变量 | | waitfor delay '0:0:10' | 时延 |

[HttpPost]
public ActionResult LoginAuthentication(
                                    LogOnModel model,
                                    string returning_url)
{
    if (ModelState.IsValid)
    {
        if (MembershipService.ValidateUser(model.UserName,
        model.Password))
        {
            FormsService.SignIn(model.UserName,
                                model.RememberMe);
            if (!String.IsNullOrEmpty(returning_url)) {
                return Redirect(returning_url);
            }
            else {
                return RedirectToAction("Index", "Home");
            }
        }
        else {
            ModelState.AddModelError("", "The credentials are
                                      wrong. Please, try again.");
        }
    }

    //** if we reach here it means that
    //** something went wrong
    //** we will show again the form
    return View(model);
}

Listing 22-1Login Controller

清单 22-2 展示了如何用returning_url进行验证。这是使用一个新方法IsLocalUrl()完成的,它是助手类System.Web.Mvc.Url的一部分。

[HttpPost]
public ActionResult LoginAuthentication(LogOnModel model, string returning_url)
{
    if (ModelState.IsValid)
    {
        if (MembershipService.ValidateUser(model.UserName,
                                           model.Password))
        {
            FormsService.SignIn(model.UserName,
                                            model.RememberMe);
            if (Url.IsLocalUrl(returning_url)){
                return Redirect(returning_url);
            }
            else {
                return RedirectToAction("Index", "Home");
            }
        }
        else {
            ModelState.AddModelError("",
                      "The credentials are wrong.
                       Please, try again.");
        }
    }

    //** if we reach here it means that
    //** something went wrong
    //** we will show again the form
    return View(model);
}

Listing 22-2Validation for returning_url

SQL 注入

对于许多公司来说,他们的业务是在网上和云计算、大数据等环境中进行的,因此他们的网站越来越暴露在数据被盗的可能性之下。黑客可以从他们的数据中获得重要信息,并将其传递给市场上的其他参与者。

SQL 注入是最常见的方法之一,恶意用户可以通过它使用网页输入将不同的 SQL 命令注入到 SQL 语句中。通过这样做,恶意用户可以破坏 web 应用的安全性。

在这一节中,我们将考虑下面的 web 应用,它是为此目的从头开始构建的。从头开始创建这样一个应用的原因是为了说明开发人员在开发过程中经常犯的错误。

第一步是建立一个包含用户登录数据的数据库。数据库是在 Microsoft SQL Server v.17.9 中创建的。图 22-1 显示了表的结构,清单 22-3 显示了生成表的 SQL 脚本代码。一个常见的错误是,许多 web 应用以明文形式存储密码。建议避免这种做法。最佳实践是使用密码的散列(如 MD5、SHA128、SHA256 等。).对于我们的例子,我们将使用明文密码。

img/493660_1_En_22_Fig1_HTML.jpg

图 22-1

表结构

USE [Apress_ProCrypto_SQLInjectionDB]
GO

/****** Object:  Table [dbo].[LoginUserData]
Script Date: 6/23/2020 2:51:06 AM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].LoginUserData NOT NULL,
     [FirstName] varchar NULL,
     [LastName] varchar NULL,
     [Email] varchar NULL,
     [Password] varchar NULL,
     [LastDateLogged] [datetime] NULL,
 CONSTRAINT [PK_LoginUserData] PRIMARY KEY CLUSTERED
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Listing 22-3Login User Data Table SQL Script

第二步是用一些数据填充表格,如图 22-2 所示。然后我们对清单 22-4 中的表执行脚本。

img/493660_1_En_22_Fig2_HTML.jpg

图 22-2

用户数据

SET NOCOUNT ON
INSERT INTO dbo.LoginUserData
              ([FirstName],[LastName],
              [Email],[Password],[LastDateLogged])
VALUES
      ('Jefferson','Nicholas','nicholas.jefferson@domain.com','password1',CONVERT(datetime,NULL,121))
      ,('Thomas','Claudio','claudio.thomas@domain.com','password2',CONVERT(datetime,NULL,121))
      ,('Steven','Paolo','steven.paolo@domain.com','password3',CONVERT(datetime,NULL,121))
      ,('Billy','Walsh','billy.walsh@domain.com','password4',CONVERT(datetime,NULL,121))

Listing 22-4Data Content

第三步是构建网络应用。为此,我们不会使用额外的花哨的 web 应用架构。这只是一个简单的 web 应用,有两个网页。到数据库的连接是使用 done 完成的。对于其他对象关系映射(ORM ),如 NHibernate、LINQ 到 SQL 或实体框架,结果是相同的。唯一的区别是处理 SQL 注入的时间长。

我们构建的第一个页面是Login.aspx。如图 22-3 所示,该页面包含一个简单的表单。代码如清单 22-5 所示。

img/493660_1_En_22_Fig3_HTML.jpg

图 22-3

Login.aspx 页面

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>

<!DOCTYPE html>

<html xmlns:="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <center>
        <form id="form1" runat="server">
        <div>
            <asp:Login ID="MyLogin" runat="server"
                   OnAuthenticate="MyLogin_Authenticate"
                   Width="331px" BackColor="#F7F6F3" BorderColor="#E6E2D8" BorderPadding="4" BorderStyle="Solid" BorderWidth="1px"
                   Font-Names="Verdana" Font-Size="0.8em" ForeColor="#333333" Height="139px">
            <InstructionTextStyle Font-Italic="True"
                                                    ForeColor="Blue" />

            <LoginButtonStyle BackColor="green"
                   BorderColor="black" BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana"
                   Font-Size="0.8em" ForeColor="#284775" />
                <TextBoxStyle Font-Size="0.8em" />
                <TitleTextStyle BackColor="green" Font-Bold="True" Font-Size="0.9em"
                   ForeColor="White" />
            </asp:Login>
        </div>
        </form>
    </center>
    <br />
    <br />
    <center>
             This example is build for illustrating SQL
             Injection. Authors: Marius Iulian MIHAILESCU and Stefania Loredana NITA
    </center>
</body>
</html>

Listing 22-5The HTML Source Code of Login.aspx

清单 22-6 显示了Login.aspx的服务器端代码。从这里你可以注意到,没有任何形式的验证密码的完整性或避免 SQL 注入攻击。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;

public partial class Login : System.Web.UI.Page
{
    DataTable data_table;
    SqlDataAdapter adapter;
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void MyLogin_Authenticate(object sender,
                                        AuthenticateEventArgs e)
    {
        SqlConnection connection = new SqlConnection(@"Data
                         Source=SERVER_NAME;Initial Catalog=Apress_ProCrypto_SQLInjectionDB;Integrated Security=True");
        string query="select * from LoginUserData where
                   Email='"+ MyLogin.UserName+"'and Password='"+
                   MyLogin.Password+"' ";
        adapter = new SqlDataAdapter(query, connection);
        data_table = new DataTable();
        adapter.Fill(data_table);
        if (data_table.Rows.Count >= 1)
        {
            Response.Redirect("index.aspx");
        }
    }
}

Listing 22-6Server Side Source Code for Login.aspx

第二个页面叫做Index.aspx,,这是一个成功登录的确认页面(参见清单 22-7 和 22-8 )。该页面没有什么特别之处。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Index : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
}

Listing 22-8Server Side Source Code for Index.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Index.aspx.cs" Inherits="Index" %>

<!DOCTYPE html>

<html xmlns:="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>APRESS-Example of SQL Injection</title>
</head>
<body>
    <form id="form1" runat="server">
    <div><center>
    <h1>Hello, Apress! <br/>
        Example for SQL Injection
    </h1></center>
    </div>
    </form>
</body>
</html>

Listing 22-7Source Code for Index.aspx

现在我们有了整个项目集,让我们继续进行 SQL 注入分析和攻击。查询如下所示:

                 select * from LoginUserData where
             Email='"+ MyLogin.UserName+"'and Password='"+
                 MyLogin.Password+"';

让我们考虑在登录控件的文本框中输入‘or 1 = 1’的情况。一旦按下登录按钮,查询将如下所示:

select  * from LoginUserData where Email=" or 1=1--'and Password="

如果攻击者知道用户名或规则 1=1,它将不再适用。他只需在文本框中写下用户名+',并对后面的所有内容进行注释,就像这样:

               select  * from LoginUserData where
          Email='nicholas.jefferson@domain.com'--and Password="

另一个危险的例子是从数据库中删除记录或删除表。以下示例显示了这种情况:

select * from LoginUserData where Email=" Delete from LoginUserData
       –'and Password="

其他类型的 SQL 注入可以在表 23-1 中看到。其中一些非常危险,不建议用于实时生产数据库。

在 ASP.NET MVC web 应用的情况下,过程与上面描述的类似。

跨站点脚本(XSS)

跨站脚本(XSS)是一个安全漏洞,攻击者在网页中插入客户端脚本,主要是 JavaScript。当用户访问 web 应用时,浏览器将加载受影响的页面,这些页面中的脚本将运行,从而为攻击者提供了获取 cookies 和会话令牌的途径。大多数情况下,当 web 应用接受用户输入并将其输出到另一个页面而不进行验证、编码或转义时,就会出现 XSS 漏洞。

根据经验,我们建议您遵循以下规则来保护您的 web 应用免受 XSS 攻击:

  • 千万不要在 HTML 页面中输入敏感数据,比如 HTML 表单输入、查询、HTTP 头等。

  • HTML 元素中的所有内容都应该被编码。

  • HTML 属性中的所有内容都应该被编码。

  • 比方说,任何需要添加到 JavaScript 中的不受信任的数据(我不喜欢这个术语,但让我们保持这种方式)应该首先输入到一个 HTML 元素中,该元素的内容应该在运行时过程中检索。

  • 在向 URL 查询字符串添加任何数据之前,请确保 URL 已编码。

例如,我们将考虑 HTML 编码如何与 MVC 中使用的 Razor 引擎一起工作,该引擎对变量的整个输出进行编码。为了避免这种情况发生,我们需要一个解决方案来防止这种情况发生。与编码相关的 HTML 属性表示 HTML 编码类型的超集,这意味着我们不需要担心应该使用 HTML 编码还是 HTML 属性编码。我们只需要确保在 HTML 上下文中使用' @ ',而不是当我们试图用 JavaScript 直接添加不可信的数据作为输入时。

让我们考虑下面清单 22-9 中的剃刀 1 视图。视图的输出将是一个untrustedInput变量。这种类型的变量在其组件中具有一些特征,这些特征可以在 XSS 攻击中被成功地利用和使用。这些角色是。在渲染输出中,编码看起来像:<&quot;testing123&quot;>

@{
       var untrustedInput = "<\"testing123\">";
   }

   @untrustedInput

Listing 22-9Example of a Razor View

有些情况下,我们希望在视图中向 JavaScript 添加要处理的值。要实现这一点,我们可以走两条路。实现这一点最安全的方法是将值放在特定标记的数据属性中,并在我们的 JavaScript 中获取它,如清单 22-10 所示。

@{
       var untrustedInput = "<\"testing123\">";
   }

   <div
       id="theDataToBeInjected"
       data-untrustedinput="@untrustedInput" />

   <script>
     var theDataToBeInjected =
            document.getElementById("theDataToBeInjected");

     //** for all the clients
     var clientWithUntrustedInput =
         theDataToBeInjected.getAttribute("data-untrustedinput");

     //** for clients that support HTML 5
     var clientWithUntrustedInputHtml5 =
         theDataToBeInjected.dataset.untrustedinput;

     document.write(clientWithUntrustedInput);
     document.write("<br />")
     document.write(clientWithUntrustedInputHtml5);
   </script>

Listing 22-10Using Razor and JavaScript Encoding

清单 22-10 中的代码将产生清单 22-11 中所示的输出。

<div
     id="theDataToBeInjected"
     data-untrustedinput="<&quot;testing123&quot;>" />

   <script>
     var theDataToBeInjected =
                   document.getElementById("theDataToBeInjected");

     var clientWithUntrustedInput =
         theDataToBeInjected.getAttribute("data-untrustedinput");;

     var clientWithUntrustedInputHtml5 =
         theDataToBeInjected.dataset.untrustedinput;

     document.write(clientSideUntrustedInputOldStyle);
     document.write("<br />")
     document.write(clientWithUntrustedInputHtml5);
   </script>

Listing 22-11The Output

一旦脚本运行,渲染结果将是

<"testing123">
   <"testing123">

同样,我们可以调用 JavaScript 编码器,如清单 22-12 所示。

@using System.Text.Encodings.Web;
   @inject JavaScriptEncoder encoder;

   @{
       var someUntrustedInput = "<\"testing123\">";
   }

   <script>
       document.write("@encoder.Encode(someUntrustedInput)");
   </script>

Listing 22-12JavaScript Encoder

一旦由浏览器呈现,我们将得到以下内容:

<script>
    document.write("\u003C\u0022testing123\u0022\u003E");
</script>

也就是说,实际上很难注意编码过程。编码发生在输出上,编码后的值不应存储在数据库或服务器上,尤其是在大数据环境中的云计算中。

结论

本章介绍了 web 应用中出现的三种常见攻击:带有重定向攻击的端口转发、SQL 注入和跨站点脚本攻击。

本章结束后,您现在可以

  • 识别 web 应用中的三种常见攻击。

  • 通过提供编程语言功能的最新支持,以专业的方式处理漏洞。

  • 理解 SQL 注入的行为方式以及如何遭遇它。

  • 通过了解可能发生的灾难,了解通过端口转发和重定向攻击暴露应用的危险。

  • 了解什么是跨站点脚本以及它们的行为方式。

文献学

  1. 使用 Razor 语法(C#)的 ASP.NET Web 编程介绍。在线可用: https://docs.microsoft.com/en-us/aspnet/web-pages/overview/getting-started/introducing-razor-syntax-c

  2. 布兰登·佩里。Gray Hat C# -创建和自动化安全工具的黑客指南。无淀粉出版社,2017。

  3. 亚当·弗里曼。Pro ASP.NET Core 3–使用 MVC Blazor 和 Razor Pages 开发云就绪型 Web 应用。2020 年出版。

  4. 斯蒂芬出没。应用密码学于 .NET 和 Azure Key Vault 。Apress,2019。

  5. 罗伯特·西斯拉。面向组织和个人的加密——当代和量子加密基础知识。2020 年出版。

二十三、文本特征

在本章中,我们将分析密码和明文分析的两个重要指标:卡方统计和模式搜索(单字母组合词、双字母组合词和三字母组合词)。当使用经典和现代密码学时,文本特征化技术是密码分析技巧包中非常重要的一部分。

卡方统计量

卡方统计是计算两个概率分布之间相似性百分比的重要度量。当卡方统计的结果等于 0 时,有两种情况:这意味着两个分布相似,如果分布非常不同,将输出更高的数字。

卡方统计由以下公式定义:

{\chi}²\left(C,E\right)=\sum \limits_{i=A}^{i=Z}\frac{{\left({C}_i-{E}_i\right)}²}{E_i}

在清单 23-1 中,我们计算了一个卡方分布的例子。

using System

namespace ComputeChiSquaredStatistics
{
   class ComputeChiSquaredStatistics
   {
      static void Main(string[] args)
      {
         int number_of_experiments=10000;
         int number_of_stars_distribution=100;

         Random theGenerator = new Random();
            double theDistribution(6.0);

         int[] probability = new int[10];

         for (int counter=0; counter
             <number_of_experiments; ++counter)
         {
               double no =
                   theDistribution(theGenerator);
              if ((no>=0.0)&&(no<10.0))
                 ++ probability [int(no)];
        }

           Console.Writeline("The Chi-Squared
            Distribution (6.0):");

            for (int index = 0; index < 10; ++index)
            {
                Console.WriteLine("index {0} ", index, " -- {1}: ",  (index + 1), ":");
                Console.WriteLine("{0}", probability[index] * number_of_stars_distribution / number_of_experiments);
            }

            Console.ReadKey();
        }
   }
}

Listing 23-1ChiSquaredDistribution Source Code

上述实现的输出如图 23-1 所示。

img/493660_1_En_23_Fig1_HTML.jpg

图 23-1

卡氏分布输出

卡方分布的例子如何帮助我们进行密码分析和加密?

第一步是计算密文中字符的出现频率。第二步是比较用于加密的假设语言(例如英语)的频率分布,并使两个频率分布彼此相关。这样我们就可以找到加密过程中使用的移位。这个过程是一个标准和简单的过程,可用于密码,如凯撒密码。当英文字符的频率与密文的频率一致时,就会发生这种情况。我们知道英语字符出现的概率

作为一个例子,让我们考虑下面这个用凯撒密码加密的例子,它有 46 个字符(字母频率见图 23-2 )。图 23-2 中的例子使用 CrypTool1T7 计算并验证加密文本上字母频率的实现及其正确性;

     ZHOFRPHWRDSUHVVWKLVLVHQFUBSWHGZLWKFDHVDUFLSKHU

理解卡方统计是基于计数而不是概率是非常重要的。例如,如果我们有一个出现概率为 0.127 的字母 E,则预期在 100 个字符内出现 12.7 次。

img/493660_1_En_23_Fig2_HTML.jpg

图 23-2

加密文本的字母频率

为了计算预期的计数,密文的长度必须乘以概率。上面的密码共有 46 个字符。根据上面 E 的统计,我们的期望是 E 字母出现 46 0.127 = 5.842 次。

为了解开凯撒密码,我们需要使用 25 个可能的密钥中的每一个,使用字母或字母在字母表中的位置。为此,计数从 0 或 1 开始非常重要。必须为每个键计算卡方。该过程包括将一个字母的计数与如果该文本是英语,我们可以预期的计数进行比较。

为了计算我们的密文的卡方统计量,我们对每个字母进行计数,我们看到字母 H 出现了 7 次。如果使用的语言是英语,应该出现 46 0.082 = 3.772 次。根据输出,我们可以计算出:

\frac{{\left(7-3.772\right)}²}{3.772}=\frac{3.228²}{3.772}=\frac{10.420}{3.772}=2.762

对剩余的字母进行该程序,并在所有概率之间进行加法运算(见图 23-3 )。

一旦密文被解密,明文应该是

          WELCOMETOAPRESSTHISISENCRYPTEDWITHCAESARCIPHER

img/493660_1_En_23_Fig3_HTML.jpg

图 23-3

加密字母频率(%) 2

使用 Monogram、Bigram 和 Trigram 频率计数的密码分析

频率分析是找到密文字符出现次数的最佳实践之一,目的是破解密码。模式分析可用于将字符作为二元模型(或有向图)进行测量和计数,这是一种测量文本中出现的字符对的方法。还有三元语法频率分析,它测量由三个字母组成的组合的出现率。

在这一节中,我们将重点关注使用二元模型和三元模型的文本特征,而不是解析密码,如 Playfair。

计数字母组合

计数字母组合是替代密码中最有效的方法之一,如凯撒密码、波利比乌斯方块等。这种方法非常有效,因为英语有特定的频率分布。这也意味着它没有被替换密码隐藏。分布将如图 23-4 和列表 23-2 所示。

img/493660_1_En_23_Fig4_HTML.jpg

图 23-4

英语的字母频率

using System;
using System.IO;

class Program
{
    static void Main()
    {
        //** we use the array to store the frequencies
        int[] frequency = new int[(int)char.MaxValue];

        //** look at the content of the text file
        string s = File.ReadAllText("TheText.txt");

        //** go through each of the characters
        foreach (char t in s)
        {
            //** store the frequencies as a table
            frequency [(int)t]++;
        }

        //** write all letters that have been found
        for (int letterPos = 0; letterPos <
                                (int)char.MaxValue; letterPos++)
        {
            if (c[letterPos] > 0 &&
                char.IsLetterOrDigit((char)letterPos))
            {
                Console.WriteLine("The Letter: {0}
                                        has the frequency: {1}",
                    (char)letterPos,
                    freq [letterPos]);
            }
        }
    }
}
}

Listing 23-2Counting Monograms

输出如图 23-5 所示。

img/493660_1_En_23_Fig5_HTML.jpg

图 23-5

计数字母组合的输出

清单 23-3 显示了进行上述计数的高级示例。这是一个使用 LINQ 和λ表达式的高级例子。图 23-6 显示了输出。

img/493660_1_En_23_Fig6_HTML.jpg

图 23-6

使用 LINQ 和拉姆达表达式的字符频率

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

namespace MonogramsCounting_LINQ{
    class Program{
        static void Main(){
            var frequencies = from c in
   File.ReadAllText("TheText.txt")
              group c by c into groupCharactersFrequencies
              select groupCharactersFrequencies;

            foreach (var c in frequencies)
                Console.WriteLine($"The character: {c.Key} has
the frequency: {c.Count()} times");

            Console.ReadKey();}}}

Listing 23-3Lambda LINQ Expression for Counting Letter Frequencies

计算二元模型

计算二元模型的方法基于与计算单字母模型相同的思想。计算二元模型意味着计算成对字符的出现频率,而不是计算单个字符的出现次数。

图 23-7 列出了密码分析过程中发现的一些常见二元模型。在清单 23-4 中,我们实现了一个处理二元模型出现次数的解决方案。图 23-8 显示输出。

img/493660_1_En_23_Fig8_HTML.jpg

图 23-8

清单 23-4 的输出

img/493660_1_En_23_Fig7_HTML.jpg

图 23-7

二元模型的例子

class Program
    {
        static void Main(string[] args)
        {
            String text = "Welcome to Apress! This book is
            about cryptography and C#.";
            String bigramPattern = "to";
            Console.WriteLine("The number of occurrences of
                  \"" + bigramPattern + "\" in \"" + text +
                  "\" is: " +
                 countFrequenciesBigrams(bigramPattern,
                                       text).ToString());

        }

        static int countFrequenciesBigrams(String
                                bigramPattern, String text)
        {
            int bigramPatternLength = bigramPattern.Length;
            int textLength = text.Length;
            int occurrences = 0;

            for (int idx = 0; idx <= textLength –
                               bigramPatternLength; idx++)
            {
                int jIdx;
                for (jIdx = 0; jIdx < bigramPatternLength;
                                                   jIdx++)
                {
                    if (text[idx + jIdx] !=
                                    bigramPattern[jIdx])
                    {
                        break;
                    }
                }

                if (jIdx == bigramPatternLength)
                {
                    occurrences++;
                    jIdx = 0;
                }
            }
            return occurrences;
        }
    }

Listing 23-4Computing Bigrams

计数三元模型

三元组计数使用与二元组计数相同的原理。区别在于计算三重字符。

图 23-9 列出了密码分析过程中遇到的一些常见二元模型。在清单 23-5 中,我们实现了一个解决方案,用于查找和计算文本中三元模型的出现次数。该解决方案与清单 23-4 中的解决方案不同。输出如图 23-10 所示。

img/493660_1_En_23_Fig10_HTML.jpg

图 23-10

清单 23-5 的输出

img/493660_1_En_23_Fig9_HTML.jpg

图 23-9

三元模型的例子

class Program
    {
        static void Main(string[] args)
        {
            String fullText = "Welcome to Apress! This book is
            about cryptography and C#.";
            String trigramPattern = "Apr";
            Console.WriteLine("Full text: " + fullText);
            Console.WriteLine("Trigram: " +
                         trigramPattern + "\n");
            Console.WriteLine("The number of occurrences of
\"" + trigramPattern + "\" in \"" +
fullText + "\" is: " +
countFrequenciesTrigrams(trigramPattern,
fullText).ToString());

        }

        static int countFrequenciesTrigrams(String
                        trigramPattern, String fullText)
        {
            int trigramPatternLength = trigramPattern.Length;
            int fullTextLength = fullText.Length;
            int noOfOccurrence = 0;

            for (int index = 0; index <= fullTextLength –
                           trigramPatternLength; index++)
            {
                int jIndex;
                for (jIndex = 0; jIndex <
                          trigramPatternLength; jIndex++)
                {
                    if (fullText[index + jIndex] !=
                                  trigramPattern[jIndex])
                    {
                        break;
                    }
                }

                if (jIndex == trigramPatternLength)
                {
                    noOfOccurrence++;
                    jIndex = 0;
                }
            }
            return noOfOccurrence;
        }
    }

Listing 23-5Counting Trigrams

生成信函频率

数组wikiFrequencies存储维基百科 3 中列出的频率(字母的相对百分比)(见清单 23-6 )。提供的示例将数字解释为百分比。例如,字母“A”出现的频率为 8.167%。

图 23-11 中的程序声明了一个Random对象。字母的定义值(如“A”)是一个整数。我们将在以后使用这个约定。事件处理器Load对来自wikiFrequencies.的所有值求和

img/493660_1_En_23_Fig11_HTML.jpg

图 23-11

字母频率的生成

using System;
using System.Linq;

namespace LetterFrequency
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "";
            VerifyFreq();

            Console.Write("The number of letters: ");
            input = Console.ReadLine();

            Compute(input);
        }

        //** Store the letter frequencies.
        //** For more details and the values
        //** stored below, see the link:
        //** http://en.wikipedia.org/wiki/Letter_frequency
        private static float[] wikiFrequencies =
        {
            8.167f, 1.492f, 2.782f, 4.253f, 12.702f,
            2.228f, 2.015f, 6.094f, 6.966f, 0.153f,
            0.772f, 4.025f, 2.406f, 6.749f, 7.507f,
            1.929f, 0.095f, 5.987f, 6.327f, 9.056f,
            2.758f, 0.978f, 2.360f, 0.150f, 1.974f,
            0.074f

        };

        //** create a instance of a number
        //** generator using Random class
        private static Random randomNumber = new Random();

        //** compute the ASCII value of letter A
        private static int int_AsciiA = (int)'A';

        //** verify that the frequencies are adding up to 100
        private static void VerifyFreq()
        {
            //** compute the difference to E
            float totalAmount = wikiFrequencies.Sum();
            float differenceComputation = 100f - totalAmount;
            wikiFrequencies[(int)'E' - int_AsciiA] +=
                         differenceComputation;
        }

        //** based on the frequencies
        //** generate randomly the letters
        private static void Compute(string txtNumLetters)
        {
            //** monitor and track each letter
            //** that has been generated
            int[] countGeneratedLetters = new int[26];

            //** randomly generate the letters
            int theNumberOfLetters = int.Parse(txtNumLetters);
            string result = "";
            for (int k = 0; k < theNumberOfLetters; k++)
            {
                //** randomly generate a number
                //** between 0 and 100
                double randomlyNumber = 100.0 *
                randomNumber.NextDouble();

                //** select the letter that
                //** this will represents
                for (int numberOfLetter = 0; ;
                                    numberOfLetter++)
                {
                    //** extract the frequency of the
                    //** letter from the number

                    randomlyNumber -=
                       wikiFrequencies[numberOfLetter];

                    //** if the randomly number is
                    //** less and equal than 0
                    //** it means that we have the letter
                    if ((randomlyNumber <= 0) ||
                              (numberOfLetter == 25))
                    {
                        char character = (char)(int_AsciiA +
                                           numberOfLetter);
                        result += character.ToString() + ' ';
                      countGeneratedLetters[numberOfLetter]++;
                        break;
                    }
                }
            }

            Console.WriteLine(result + "\n");

            //** show the frequencies
            for (int i = 0; i < countGeneratedLetters.Length;
                                                  i++)
            {
                char ch = (char)(int_AsciiA + i);
                float frequency =
(float)countGeneratedLetters[i] /
theNumberOfLetters * 100;
                string str =
string.Format("{0}\t{1,6}\t{2,6}\t
{3,6} ,ch.ToString(),
frequency.ToString("0.000"),
wikiFrequencies[i].ToString("0.000"),
(frequency –
wikiFrequencies[i]).ToString("0.000"));

                Console.WriteLine(str);
            }
        }
    }
}

Listing 23-6Randomly Generating Letter Frequencies

结论

本章介绍了文本特征的概念,并展示了它在密码分析过程中的重要性。现在,您可以处理卡方统计,并使用单字母组合词、双字母组合词和三字母组合词来解密替代密文。作为总结,您了解了

  • 文本特征的概念

  • 使用字母组合、二元组合和三元组合

  • 卡方统计的实现

  • Monogram、digram 和 trigram 实现

文献学

  1. 西蒙·辛格,《密码本:从古埃及到量子密码术的秘密科学》。国际标准书号 0-385-49532-3。2000.

  2. 《密码分析:对密码及其解决方案的研究》, 1989 年。

Footnotes 1

密码学门户网站, www.cryptool.org/en/

  2

字母加密频率使用 CrypTool 生成, www.cryptool.org/en/

  3

http://en.wikipedia.org/wiki/Letter_frequency 信频。

 

二十四、密码分析方法的实现和实用途径

在这一章中,我们想提出一个密码分析方法的方法论,以及如何快速有效地应用它。该方法用于经典和实际(现代)密码术/密码分析算法和方法。目前不包括量子密码术。

所提出的方法(见图 24-1 )旨在让密码分析人员知道他们在工作中的位置和位置,以及他们可以相应地使用什么工具或方法。

img/493660_1_En_24_Fig1_HTML.jpg

图 24-1

密码分析方法

如果您没有关于加密方法的适当信息,实现密码分析方法是一项非常棘手的任务。也就是说,密码分析过程包括两个一般步骤。第一步包括确定应该执行哪种密码分析,第二步包括我们所知道的密码算法。基于这两个步骤,我们可以转到步骤 3* 来构建合适的攻击模型步骤 4 来选择合适的工具。*

*第一步。*应该进行什么样的密码分析?在这里,密码分析员决定,连同他们的商业环境,他们将扮演什么样的角色:一个合法的和授权的密码分析员(道德黑客)或一个恶意的(黑客)。一旦他们决定了自己的角色,他们就进入第二步。

第二步。如果他们是一个合法的密码分析者,在开始之前有两件事他们应该知道:?? 密码算法和 ?? 密钥。根据一些密码分析者,这不是一个必要的要求,但在某些情况下,知道这一点是非常有用的。一旦知道了这两件事,他们就可以很容易地执行密码分析方法,并测试业务的安全性。

*第三步。*当攻击模型或攻击类型对加密消息执行破解方法时,它们将为密码分析能够获得多少信息设置一个量化变量。最常用的攻击模型有

  • 唯密文攻击

  • 已知明文攻击

  • 选择明文攻击

  • 选择密文攻击

    • 自适应选择密文攻击

    • 无差别选择密文攻击

第四步。一旦选择了攻击模型,或者根据情况和要求创建并调整了另一个模型,下一步就是选择软件工具。有两种方法,从已经存在的工具中选择或者创建自己的工具(这很费时间,但是很好的实践)。下面是一些我们可以在密码分析过程中使用的工具的例子,这取决于我们试图“测试”什么

  • 渗透工具:Kali Linux,Parrot Security,BackBox

  • 法医:DEFT,CAINE,BlackArch,Matriux

  • 数据库:sqlmap(独立版)、Metasploit 框架(独立版)、VulDB

  • Web 和网络:Wireshark、Nmap、Nessus、Burp Suite、Nikto、OpenVas

  • 其他工具:CryptTool(非常有用和神奇的工具)

上面提到的工具只代表了那些非常强大并且能够产生预期结果的工具中的一部分。

纯密文攻击(COA)

COA 是最弱的攻击之一,因为密码分析者可以很容易地使用它,因为他只是对消息进行编码。

攻击者(密码分析员)将有权访问一组密文。如果相应的明文和密钥一起被推断出来,攻击就被认为是成功的。

在这种类型的攻击中(见图 24-2 ),攻击者/密码分析师能够观察到密文。他们所看到的是一组被打乱的无意义的字符,这些字符被表示为加密过程的输出。

img/493660_1_En_24_Fig2_HTML.jpg

图 24-2

COA 表示

已知明文攻击

这种攻击(见图 24-3 )赋予了密码分析者生成密文的能力,因为他知道密文。

img/493660_1_En_24_Fig3_HTML.jpg

图 24-3

KPA 表示法

密码分析员会选择明文,但他们会注意到由明文和密文组成的密码对。与 COA 相比,成功的机会更大。简单的密码很容易受到这种攻击。

选择明文攻击

密码分析员选择使用加密算法发送的明文,并观察密文是如何生成的。这可以看作是一种主动模型,其中密码分析者有机会选择明文并实现加密。

由于可以选择任何明文,密码分析者也可以观察到密文的细节,这给了他很大的优势来理解算法内部是如何工作的,并有机会获得密钥。

一个专业的密码分析人员将拥有一个数据库,其中包含已知的明文、密文和可能的密钥(参见清单 24-1 和图 24-5 中自动生成可能密钥的示例;这是一个说明要点的非常简单的例子),并使用它们来确定密文输入(见图 24-4 )。

img/493660_1_En_24_Fig4_HTML.jpg

图 24-4

注册会计师代表

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

namespace GeneratingKeysDatabase
{
    class Program
    {
        public static string size = Console.ReadLine();
        public static int values_based_on_length =
            Convert.ToInt32(size);
        public char first_character = 'a';
        public char last_character = 'z';
        public int string_length = values_based_on_length;

        static void Main(string[] args)
        {
            var writting_password = new Program();
            writting_password.WrittingPasswordsAndKeys(" ");
            Console.ReadLine();
        }

        //** automatically generates the
        //** passwords and create a file
        private void WrittingPasswordsAndKeys(string
                                              cryptographic_passwords)
        {
            //** location and file name that
            //** contains the passwords
            string file = "passwords_database.txt";

            //** add on each row a new password
            File.AppendAllText(file, Environment.NewLine +
                                              cryptographic_passwords);

            //** display it on the console
            Console.WriteLine(cryptographic_passwords);

            //** don't do anything if the length of the
            //** passwords is equal with the length of
            //** the string and continue with generating
            //** the passwords and keys
            if (cryptographic_passwords.Length ==
                                                 string_length)
            {

                return;
            }
            for (char c = first_character; c <=
                                                last_character; c++)
            {
                  WrittingPasswordsAndKeys(
                                           cryptographic_passwords + c);
            }
        }
    }
}

Listing 24-1Automatic Generation of Random Keys

img/493660_1_En_24_Fig5_HTML.jpg

图 24-5

生成的密钥和可能的密码。我们选择三个字符只是为了短时间处理

选择密文攻击

密码分析员有机会加密和解密信息。在这种攻击中(见图 24-6 ),他们有能力选择明文,为其提供加密,观察密文是如何生成的,并反转整个过程。在这种攻击中,密码分析人员还将试图找到用于加密的算法和密钥。

img/493660_1_En_24_Fig6_HTML.jpg

图 24-6

CCA 代表

结论

在这一章中,我们讨论了如何实现密码分析方法以及如何为密码分析者定义这样的过程。在本章结束时,您将能够

  • 对攻击模型有很好的理解

  • 遵循简单直接的方法来了解您在密码分析过程中的位置

  • 用密钥和可能的密码模拟并生成一个数据库

文献学

  1. Abu Yusuf yaqub ibn ishaq al-sabbah al-kindiwww.trincoll.edu/depts/phil/philo/phils/muslim/kindi.html

  2. 哲学家:亚库卜·伊本·伊扎克·肯尼迪日、k·金迪、阿布·优素福·亚库卜·伊本·伊沙克(草 866-73)。 www.muslimphilosophy.com/ip/kin.html

  3. Ahmad Fouad Al-Ehwany,穆斯林哲学史第 1 卷中的“Al-Kindi”。新德里:低价出版物。第 421-434 页。1961.

  4. Ismail R. Al-Faruqi 和 Lois Lamya al-Faruqi,伊斯兰文化图集,纽约:麦克米伦出版公司。第 305-306 页。1986 年大英百科全书公司(1969 年)。大英百科全书。芝加哥:威廉·本顿。

  5. J.J .奥康纳和 E.F .罗伯逊,E.F. 阿布·优素福·雅各布·伊本·伊斯哈格·萨巴·金迪。1999.

第一部分:基础主题

第二部分:密码

第三部分:密码分析