Python 密码学实用指南(全)(2)

简介: Python 密码学实用指南(全)

Python 密码学实用指南(全)(1)https://developer.aliyun.com/article/1507496

base64 编码

我们现在将讨论将 ASCII 数据编码为字节,并对这些字节进行 base64 编码。我们还将涵盖二进制数据的 base64 编码和解码,以恢复原始输入。

ASCII 数据

在 ASCII 中,每个字符变成一个字节:

  • A在十进制中是65,在二进制中是0b01000001。这里,你在最高位没有128,然后在下一个位上有641,最后有1,所以你有64 + 1=65
  • 接下来是B,基数为66C,基数为67B的二进制是0b01000010C的二进制是0b01000011

三个字母的字符串ABC可以解释为一个 24 位的字符串,看起来像这样:


我们添加了这些蓝线只是为了显示字节的分隔位置。要将其解释为 base64,你需要将其分成 6 位一组。6 位有 64 种组合,所以你需要 64 个字符来编码它。

使用的字符如下:


我们使用大写字母表示前 26 个,小写字母表示另外 26 个,数字表示另外 10 个,总共 62 个字符。在最常见的 base64 形式中,最后两个字符使用+/


如果你有一个 ASCII 字符串有三个字符,它变成 24 位,解释为 3 组 8 位。如果你把它们分成 4 组 6 位,你有 4 个 0 到 63 之间的数字,在这种情况下,它们变成QUJD。在 Python 中,你只需要一个字符串,后面跟着命令:

>>> "ABC".encode("base64")
'QUJD\n'

这将进行编码。然后在最后添加一个额外的回车,这既不重要也不影响解码。

如果你有的不是 3 个字节的组合呢?

等号=用于指示填充,如果输入字符串长度不是 3 个字节的倍数。

如果输入有四个字节,那么 base64 编码以两个等号结束,只是表示它必须添加两个填充字符。如果有五个字节,就有一个等号,如果有六个字节,那么就没有等号,表示输入完全适合 base64,不需要填充。填充是空的。

你取ABCD进行编码,然后你取ABCD并加上一个显式的零字节。x00表示一个具有八位零的单个字符,你得到相同的结果,只是多了一个A和一个等号,如果你用两个零字节填满它,你会得到大写的A。记住:大写的Abase64中的第一个字符。它代表六位零。

让我们来看看 Python 中的 base64 编码:

  1. 我们将启动python并创建一个字符串。如果你只是用引号创建一个字符串并按Enter,它会立即打印出来:
>>> "ABC"
'ABC'
  1. Python 会自动打印每次计算的结果。如果我们用base64对其进行编码,我们会得到这个结果:
>>> "ABC".encode(""base64")
'QUJD\n'
  1. 它变成QUJD,最后有一个额外的回车,如果我们让它更长:
>>> "ABCD".encode("base64")
'QUJDRA==\n'
  1. 这里有两个等号,因为我们从四个字节开始,它必须再添加两个字节使其成为 3 的倍数:
>>> "ABCDE".encode("base64")
'QUJDREU=\n'
>>> "ABCDEF".encode("base64")
'QUJDREVG\n'
  1. 有五个字节的输入,我们有一个等号;有六个字节的输入,我们没有等号,而是一共有八个字符使用base64
  2. 让我们回到带有两个等号的ABCD
>>>"ABCD".encode("base64")
'QUJDRA==\n'
  1. 你可以看到填充是如何通过在这里明确放置它来完成的:
>>> "ABCD\x00\x00".encode("base64")
'QUJDRAA=\n'

有一个零的第一个字节,现在我们得到另一个单个等号。

  1. 让我们再加入一个字节的零:
>>> "ABCD\x00\x00".encode("base64")
'QUJDRAAA\n'

这里没有填充,我们看到最后的字符都是A,表明已经填充了二进制零。

二进制数据

下一个问题是处理二进制数据。可执行文件是二进制的,而不是 ASCII。此外,图像、电影和许多其他文件都包含二进制数据。ASCII 数据始终以第一个位为零开始,但base64可以很好地处理二进制数据。这是一个常见的可执行文件,一个法医实用程序;它以MZê开头,并且有不可打印的 ASCII 字符:


由于这是一个十六进制查看器,您可以看到十六进制的原始数据,在右侧,它尝试将其打印为 ASCII。Windows 程序在开头有这个字符串,并且这个程序不能在 DOS 模式下运行,但它们有很多不可打印的字符,比如FF0,这对 Python 来说并不重要。像这样编码数据的简单方法是直接从文件中读取它。您可以使用with命令。它将使用文件名和读取二进制模式打开一个文件,并使用句柄f读取它。with命令在这里只是告诉 Python 打开文件,并且如果由于某些错误无法打开文件,则关闭句柄,然后以完全相同的方式解码它。要解码以这种方式编码的数据,只需取输出字符串,并将.encode替换为.decode

现在让我们看看如何处理二进制数据:

  1. 我们将首先退出 Python,以便我们可以查看文件系统,然后我们将使用以下命令查找Ac文件:
>>> exit()
$ ls Ac*
AccessData Registry Viewer_1.8.3.exe

这是文件名。由于这是一个比较长的块,我们只需复制并粘贴它。

  1. 现在我们启动 Python 并使用以下命令clear屏幕:
$ clear
  1. 我们将重新开始python
$ python
  1. 好的,现在我们使用以下命令:
>>> with open("AccessData Registry Viewer_1.8.3.exe", "rb") as f:
... data = f.read()
... print data.encode("base64")

这里我们首先输入文件名,然后是读取二进制模式。我们将给它一个文件名句柄f。我们将获取所有数据并将其放入一个单一变量数据中。我们可以只对数据进行base64编码,它会自动打印出来。如果您在 Python 中有一个预期的块,您必须按Enter键两次,以便它知道块已完成,然后base64对其进行编码。

  1. 您会得到一个很长的base64块,这不太可读,但这是处理这种数据的一种方便方式;比如,如果您想要通过电子邮件发送它或将其放入其他文本格式中。因此,为了进行解码,让我们编码一些更简单的东西,以便我们可以轻松地看到结果:
>>> "ABC".encode("base64")
'QUJD\n'
  1. 如果我们想要使用它,可以使用以下命令将其放入一个c变量中:
>>> c = "ABC".encode("base64")
>>> print c
QUJD
  1. 现在我们可以打印c以确保我们得到了预期的结果。我们有QUJD,这是我们预期的结果。所以,现在我们可以使用以下命令对其进行解码:
>>> c.decode("base64")
'ABC'

base64不是加密。它不隐藏任何东西,而只是另一种表示方法。在下一节中,我们将介绍 XOR。

XOR

本节解释了 XOR 在单个位上的真值表,然后展示了如何在字节上进行操作。XOR 可以撤销自身,因此解密与加密是相同的操作。您可以使用单个字节或多个字节密钥进行 XOR,并且我们将使用循环来测试密钥。以下是 XOR 的真值表:

  • 0 ^ 0 = 0
  • 0 ^ 1 = 1
  • 1 ^ 0 = 1
  • 1 ^ 1 = 0

如果您输入两个位,并且这两个位相同,则答案是0。如果位不同,则答案是1

XOR 一次操作一个位。Python 使用^运算符表示 XOR。

真值表显示了它的工作原理。您输入可能是01的位,并将它们进行异或运算,然后最终得到 50%的 1 和 0,这意味着异或不会破坏任何信息。

这是字节的异或:

  • A 0b01000001
  • B 0b01000010
  • XOR 0b00000011

A是数字65,所以你有64111B大 1,如果你将它们进行 XOR 操作,所有的位匹配前 6 位,它们都是0。最后两位不同,它们变成了1。这是二进制值3,它不是一个可打印的字符,但你可以将它表示为一个整数。

密钥可以是单字节或多字节。如果密钥是单字节,比如B,那么你可以使用相同的字节来加密每个明文字符。只需一直重复使用密钥:


为这个字节重复B,那个字节也是B,依此类推。如果密钥是多字节的,那么你就重复这个模式:


你用B代表第一个字节,C代表下一个字节,然后再次用B代表下一个字节,C代表下一个字节,依此类推。

在 Python 中,你需要循环遍历字符串的字节并计算一个索引来显示你所在的字节。然后我们从用户那里输入一些文本,计算它的长度,然后遍历从1到字符串长度的索引,从0开始。然后我们取文本字节并在这里打印出来,这样你就可以看到循环是如何工作的。所以,如果我们给它一个五个字符的明文,比如HELLO,它就会一个接一个地打印出字符。

要进行异或操作,我们将输入一个明文和一个密钥,然后取一个文本字节和一个密钥字节,进行异或操作,然后打印出结果。

注意%len( key),这可以防止你超出密钥的末尾。它将一直重复密钥中的字节。因此,如果密钥是三个字节长,这将是模三,所以它将计数为012,然后回到0 1 2 0 1 2,依此类推。这样,你可以处理任意长度的明文。

如果你结合大写和小写字母,你经常会发现 XOR 产生无法打印的字节的情况。在接下来的例子中,我们使用了HELLOKitty和一个qrs的密钥。请注意,其中一些字节是可以打印的,而其中一些包含奇怪的字符,比如EscTab,这些很难打印。因此,处理输出的最佳方式不是尝试将其作为 ASCII 打印,而是将其作为hex编码的值打印。我们不是一个接一个地打印字节,而是将它们组合成一个cipher变量,最后,我们以hex形式打印出整个明文,整个密钥,然后是整个密文。这样,它可以正确处理这些难以打印的奇怪值。

让我们在 Python 中尝试这个循环:

  1. 我们打开终端并输入以下命令:
$ nano xor1.py
  1. 当你运行它时,你会得到以下输出:


  1. 这是第一个xor1.py,所以我们从用户那里输入文本,计算它的长度,然后一个接一个地打印出字节,以查看循环是如何工作的。让我们运行它并给它HELLO


  1. 它只是一个接一个地打印出字节。现在,让我们看一下下一个 XOR 2:


这里输入textkey,然后以相同的方式进行处理,遍历text的每个字节,使用模运算挑选出key的正确字节,执行异或操作,然后打印出结果。

  1. 所以如果我们在这里运行相同的文件,我们取HELLO和一个key如下所示:
$ nano xor2.py
$ python xor2.py

因此,输出如下:


它逐个计算字节。请注意,这里我们得到了两个等号,这就是为什么你会使用多字节key的原因,因为明文在变化,但密钥也在变化,而这种模式在输出中没有反映出来,所以它是更有效的混淆。

  1. 清除并查看第三个xor2a.py文件:


这样你就可以看到,这解决了无法打印的字节的问题。

  1. 因此,我们创建了一个名为cipher的变量,在这里组合了每个输出字节,最后,我们用hex编码它,而不是直接尝试将其打印出来:


  1. 如果你给它HELLO,然后输入一个qrs的键,它会给你明文HELLO Kitty,键,然后是十六进制编码的输出,这可以轻松处理有趣的字符,比如0 70 5。在下一节中,你将看到挑战 1 – 凯撒密码。

挑战 1 – 凯撒密码

经过凯撒密码的复习,我们将有一个解决它的例子,然后是你的挑战。记住凯撒密码是如何工作的。你有一个可用字符的字母表,你输入消息和一个shift值,然后你只需将字符向前移动那么多步,如果超出字母表的末尾就回到开头。我们最终得到的脚本适用于任何shift值,包括正常的数字,比如3,甚至大于26的数字;它们只是循环并且可以混淆你输入的任何数据。

这是一个例子:

  1. 对于密文,你可以尝试从025的所有shift值,其中一个将是可读的。这是一个简单的暴力攻击。让我们来看看。

在这里,在 Python 中,去caesar4脚本,我们之前有过。它接受一个字符串并将其按你指定的任何值进行移位。如果我们使用那个脚本,我们可以运行它如下:


  1. 然后,如果我们输入HELLO并将其移位3,它就会变成KHOOR
  2. 如果我们想要破解它,我们可以使用以下解决方案脚本:


  1. 所以,如果我们使用那个脚本,我们可以运行它:


  1. 如果我们输入KHOOR,它将以各种值进行移位,你可以看到在23时可读的值是HELLO。所以,我们之前讨论的更长的密文等等的例子,在3时变得可读,你会看到它是DEMONSTRATION


  1. 你的挑战是解密这个字符串:MYXQBKDEVKDSYXC

在下一节中,我们将有一个关于base64的挑战。

挑战 2 – base64

经过base64的复习,我们将进行一个例子,向你展示如何解码一些混淆的文本,然后我们为你准备了一个简单的和一个困难的挑战。

这是base64的复习:


base64编码文本会变得更长。这是要解码的示例文本:

U2FtcGxliHRleHQ=

它解码成示例文本字符串。让我们看看。

参考以下步骤:

  1. 如果你在立即模式下运行python,它将执行四个简单的任务:
$ python
  1. 所以,如果我们取ABC并用base64编码,我们会得到这个字符串:
>>> "ABC".encode("base64")
'QUJD\n'
  1. 如果我们用base64解码它,我们会得到原始文本:
>>> "QUJD".decode("base64")
'ABC'
  1. 所以,挑战文本如下,如果你解码它,你会得到示例文本字符串:
>>> "U2FtcGxliHRleHQ=".decode("base64")
'Sample text'
  1. 这对于简单情况足够了;你的第一个挑战看起来是这样的:
Decode this: VGhpcyBpcyB0b28gZWFzeQ==
  1. 这是一个要解码的长字符串,用于你的更长的挑战:
Decode this:
VWtkc2EwbEliSFprVTJeFl6SlZaMWxUUW5OaU1qbDNVSGM5UFFvPQo=

这个长字符串之所以这么长,是因为它被base64编码了不止一次,而是多次。所以,你需要尝试解码它,直到它变成可读的内容。在下一节中,我们将有挑战 3 – 异或

挑战 3 – 异或

在这一节中,我们将复习异或的工作原理,然后给你一个例子,然后提出两个挑战。

所以,这是我们之前讨论过的一个异或程序:


你输入任意文本和一个任意的键,然后逐个字节地遍历它们,挑选出一个文本字节和一个键字节,然后用异或结合它们并打印出结果。所以,如果你输入HELLOqrs,你会得到用异或加密的东西。

这里有一个例子:


它会解密成EXAMPLE。所以,这是解密;记住异或会解开自己。

如果你想破解其中一个,一个简单的方法就是尝试每个键并打印出每个结果,然后读出可读的键。

所以,我们尝试从09的所有单个数字键。

结果是你输入密文,用每个值加密它,当你得到正确的键值时,它将变成可读的文本。

让我们来看看:


这是解密例程,它简单地从用户输入文本,然后尝试这个字符串中的每个密钥,09。对于这些中的每一个,它将 XOR 文本组合成一个名为clear的变量,以便可以为每个密钥打印一行,然后清晰结果。因此,如果我们运行它并输入我的密文,它会给我们 10 行。


我们只是浏览了这些行并看到哪一个变得可读,您可以看到正确的密钥和正确的明文在6处。第一个挑战就在这里:


这与我们之前看到的类似。密钥是一个数字,它将解密为可读的内容。这是一个以十六进制格式的更长的示例:


密钥是两个 ASCII 数字,因此您将不得不尝试 100 种选择来找到将其转换为可读字符串的方法。

总结

在本章中,设置 Python 之后,我们介绍了简单的替换密码、凯撒密码,然后是base64编码。我们每次收集六位数据而不是八位数据,然后我们看了 XOR 编码,其中位根据密钥逐个翻转。我们还看到了一个非常简单的真值表。您完成的挑战是破解凯撒密码而不知道密钥,通过将base64反向解码以获取原始字节,并尝试所有可能的密钥进行暴力攻击来破解 XOR 加密。在第二章 哈希中,我们将介绍不同类型的哈希算法。

第二章:哈希

哈希有两个主要目的:第一个是在文件上放置一个指纹,以便您可以判断它是否已被更改,第二个是隐藏密码,以便您仍然可以识别正确的密码并启用登录,但是窃取哈希的人不能轻松地从中恢复密码。

在本章中,我们将涵盖以下主题:

  • MD5 和 SHA 哈希
  • Windows 密码哈希
  • Linux 密码哈希
  • 挑战 1 - 破解 Windows 哈希
  • 挑战 2 - 破解多轮哈希
  • 挑战 3 - 破解 Linux 哈希

MD5 和 SHA 哈希

在解释哈希函数是什么之后,我们将处理 MD5,然后是 SHA 系列:SHA-1,SHA-2 和 SHA-3。我们还将获取一些关于破解哈希的信息。

哈希是什么?

如前所述,使用哈希的一个目的是在文件上放置一个指纹。您可以使用哈希算法将文件中的所有字节组合在一起,从而创建一个固定的哈希值。如果更改文件的任何部分并重新计算哈希,则会得到完全不同的值。因此,如果您有两个应该相同的文件,您可以计算每个文件的哈希值,如果两个文件的哈希值匹配,则文件相同。

一个非常常见的哈希是 MD5;它已经存在了几十年。它的长度为 128 位,对于哈希函数来说相当短,对于大多数目的来说足够可靠。人们用它来对下载和恶意软件样本等进行指纹识别,有时也用于隐藏密码。它不是一个完美的哈希函数:已知有一些碰撞,并且有一些算法可以在一些计算时间的代价下创建碰撞,这些碰撞是哈希到相同值的文件对。因此,如果您找到两个具有匹配 MD5 的文件,您并不完全确定它们是相同的文件,但它们通常是。

在 Python 中计算它们非常容易。您只需导入哈希库,然后进行计算。您调用哈希库来创建一个新对象。第一个参数是使用的算法,即 MD5。第二个参数是要进行哈希处理的数据的内容。

在这里,我们将使用HELLO作为示例,然后您需要在末尾使用十六进制摘要,否则它将只打印数据结构的地址,而不是显示实际值。我们将使用HELLO的哈希,MD5 和十六进制,它有 128 位长。因此,这是 128 除以 4,或 32 个十六进制字符,如果您向HELLO添加另一个字符,比如感叹号,哈希将完全改变;一个值的哈希与下一个值的哈希之间没有任何相似之处。

安全哈希算法SHA)旨在改进 MD5,直到大约一年前,SHA-1 没有发生碰撞,当时一些谷歌公司的研究人员发现了如何在 SHA-1 中发生碰撞,因此谨慎的人们正在转向 SHA-2。还有另一个由国家标准技术研究所批准的算法,称为SHA-3,几乎没有人使用,因为据所有人的预期,SHA-2 将在很长一段时间内保持安全。但是,如果发生了危及 SHA-2 的情况,SHA-3 将可供我们使用。SHA-2 和 SHA-3 都有各种长度,但最常见的长度是 256 和 512 位。

您可以在 Python 中轻松计算 SHA-1 和 SHA-2 哈希,但 SHA-3 并不常用,它还不是这个哈希库的一部分。因此,如果您使用 SHA-1 算法,您将得到一个 SHA-1 哈希。它看起来像 MD5 哈希,但更长。然后有 SHA-256 和 SHA-512,它们都是 SHA-2 哈希。您可以看到,尽管它们更安全,但它们更长,而且有些不太方便:


所以,让我们来看看。

打开终端并执行python命令以启动 Python 终端:


然后,您可以运行以下命令:


您必须导入hashlib。然后,您可以添加hashlib.new。第一个参数是算法,这种情况下是md5。下一个参数是要进行哈希的数据,这里是HELLO,然后添加hexdigest以查看十六进制值。所以,这是HELLO的哈希,如果我们在末尾添加另一个字符,使其变成HELLOa,那么我们会得到一个完全不同的答案。


如果我们想使用不同的算法,我们只需输入 SHA-1:


现在我们得到了一个很长的哈希值,如果我们添加sha256作为字符,我们会得到一个更长的哈希值:


这些哈希对于几乎任何目的都足够了。

如果您有某物的哈希值,并且想要计算它来自哪些数据,原则上,这并没有唯一的解决方案。不过,在实践中,对于像密码这样的短对象,是有的。因此,如果有人使用MD5函数来隐藏密码,这是一些旧的 Web 应用程序所做的,那么您可以通过猜测密码来反转它,直到找到匹配项。没有数学方法可以撤消哈希函数,因此您只需制作一个库。在MD5哈希HELLO的示例中,如果您只是进行一系列猜测,您将得到正确的答案。这就是哈希破解的工作原理;这不是一个复杂的想法,只是有点不方便。

我们可以获取HELLO的 MD5 哈希并继续猜测:


如果我们在猜测单词,可能需要猜测数百万个单词才能得到所示的值,但是如果我们能够猜到正确的值,当哈希值匹配时,我们就知道它是正确的。这个的难度取决于您每秒可以计算多少个哈希值,而 MD5 和 SHA 系列都设计为非常快速计算,因此您实际上可以尝试数百万个密码。在下一节中,我们将讨论 Windows 密码哈希。

Python 密码学实用指南(全)(3)https://developer.aliyun.com/article/1507501

相关文章
|
7天前
|
存储 安全 网络安全
Python网络安全与密码学
【5月更文挑战第23天】 探索Python在网络安全与密码学的实践,从加密算法(如AES、RSA)和哈希函数(MD5、SHA-256)到网络安全工具(Scapy、Socket)的应用。了解如何使用PyCryptodome和hashlib进行加密解密及哈希计算,通过Scapy进行网络数据包操作和端口扫描,利用Socket实现TCP通信。深入密码学,学习RSA加密和数字签名,以及使用Django和Flask实现安全Web开发。此外,掌握高级网络安全技术,如Wireshark流量分析、Bro/Zeek入侵检测,以及自动化安全运维(Ansible)和安全数据分析(Pandas、Matplotlib)。
10 2
|
22天前
|
安全 算法 物联网
Python 密码学实用指南(全)(4)
Python 密码学实用指南(全)
9 0
|
22天前
|
算法 Linux 数据安全/隐私保护
Python 密码学实用指南(全)(3)
Python 密码学实用指南(全)
13 1
|
22天前
|
Linux 数据安全/隐私保护 iOS开发
Python 密码学实用指南(全)(1)
Python 密码学实用指南(全)
17 1
|
12月前
|
数据安全/隐私保护 Python
Python——实现密码学中的模逆运算
Python——实现密码学中的模逆运算
194 0
|
12月前
|
Python
Python——验证密码学常见运算
Python——验证密码学常见运算
59 0
|
安全 算法 数据安全/隐私保护