如何在Python中实现加密消息签名和验证---HMAC

1,088 阅读4分钟

Python为加密任务提供了各种内置算法。这篇文章将演示hmac加密任务的内置算法之一**,用于使用Python的加密消息签名和验证**,并通过Python4Delphi在Python GUI中运行以获得结果。

hmac模块实现了用于消息验证的键合,如RFC 2104中所述。HMAC算法可以用来验证应用程序之间传递的信息的完整性,或者存储在一个有潜在风险的位置。

其基本思想是生成实际数据的加密散列,并结合共享的秘密密钥。然后,产生的哈希值可以用来检查传输或存储的信息,以确定信任程度,而不需要传输秘密密钥。

这篇文章将指导你

如何在Windows GUI应用程序中使用内置的hmac库实现Python加密服务?

先决条件 在我们开始工作之前,请下载并安装你所在平台的最新 Python。按照 这里提到的 Python4Delphi安装说明。或者,你也可以查看这个视频中的简单说明 开始使用Python4Delphi

首先,使用Python4Delphi与RAD Studio的项目Demo1打开并运行我们的Python GUI。然后将脚本插入下层备忘录中,点击执行按钮,在上层备忘录中得到结果。你可以在 GitHub上找到Demo1的源代码。关于Delphi如何在这个神奇的Python GUI中运行你的Python代码的幕后细节可以在这个 链接中找到。

How To Sign and Verify Cryptographic Messages In Your Apps - demo screen

打开Demo01.dproj

我们如何使用二进制摘要来产生可打印的摘要?

让我们尝试一个二进制摘要的例子,以产生可打印的摘要。一些网络服务(Google checkout, Amazon S3)使用base64编码的二进制摘要而不是hexdigest。在Python4Delphi GUI中运行以下代码。

import base64
import hmac
import hashlib

with open('lorem.txt', 'rb') as f:
    body = f.read()

hash = hmac.new(
    b'secret-shared-key-goes-here',
    body,
    hashlib.sha1,
)

digest = hash.digest()
print(base64.encodebytes(digest))

base64编码的字符串在新的一行中结束,当把字符串嵌入http头或其他对格式敏感的环境中时,经常需要把它剥离出来。让我们看看Python GUI中的输出。

How To Sign and Verify Cryptographic Messages In Your Apps - the app, in action

如何用Python实现消息签名的应用?

接下来,让我们尝试一个更高级的例子消息签名的应用。HMAC认证应该被用于任何公共网络服务,以及任何存储数据的时间,而这些时间的安全性是很重要的。例如,当通过管道或套接字发送数据时,该数据应该被签名,然后在使用该数据之前对签名进行测试。

以下是实现消息签名应用的步骤:

  • 建立一个函数来计算一个字符串的摘要,并建立一个简单的类来实例化并通过通信通道传递。
  • 创建一个BytesIO缓冲区来表示套接字或管道。这个例子对数据流使用了一种天真的、但容易解析的格式。数据的摘要和长度被写入,后面是一个新行。接下来是由pickle生成的对象的序列化表示。
  • 对于这个例子的程序,写两个对象到流中。第一个对象是用正确的摘要值写的。第二个对象用一个无效的摘要写到流中,这个摘要是通过对其他一些数据而不是pickle的数据计算出的。
  • 现在数据在BytesIO缓冲区中,它可以被再次读出来。首先读取带有摘要和数据长度的那行数据。然后读取剩余的数据,使用长度值。pickle.load()可以直接从数据流中读取,但是这假设了一个可信的数据流,而这个数据还没有被信任到足以解开它。从流中以字符串的形式读取pickle,而不实际解开对象,是比较安全的。
  • 一旦提取的数据在内存中,可以重新计算摘要值,并使用compare_digest()与读取的数据进行比较。如果摘要匹配,就可以安全地相信数据并解开它。
import hashlib
import hmac
import io
import pickle
import pprint

def make_digest(message):
    "Return a digest for the message."
    hash = hmac.new(
        b'secret-shared-key-goes-here',
          message,
          hashlib.sha1,
    )
    return hash.hexdigest().encode('utf-8')

class SimpleObject:
    """Demonstrate checking digests before unpickling.
    """
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

# Simulate a writable socket or pipe with a buffer
out_s = io.BytesIO()

# Write a valid object to the stream:
#  digestnlengthnpickle
o = SimpleObject('digest matches')
pickled_data = pickle.dumps(o)
digest = make_digest(pickled_data)
header = b'%s %dn' % (digest, len(pickled_data))
print('WRITING: {}'.format(header))
out_s.write(header)
out_s.write(pickled_data)

# Write an invalid object to the stream
o = SimpleObject('digest does not match')
pickled_data = pickle.dumps(o)
digest = make_digest(b'not the pickled data at all')
header = b'%s %dn' % (digest, len(pickled_data))
print('nWRITING: {}'.format(header))
out_s.write(header)
out_s.write(pickled_data)

out_s.flush()

# Simulate a readable socket or pipe with a buffer
in_s = io.BytesIO(out_s.getvalue())

# Read the data
while True:
    first_line = in_s.readline()
    if not first_line:
        break
    incoming_digest, incoming_length = first_line.split(b' ')
    incoming_length = int(incoming_length.decode('utf-8'))
    print('nREAD:', incoming_digest, incoming_length)

    incoming_pickled_data = in_s.read(incoming_length)

    actual_digest = make_digest(incoming_pickled_data)
    print('ACTUAL:', actual_digest)

    if hmac.compare_digest(actual_digest, incoming_digest):
        obj = pickle.loads(incoming_pickled_data)
        print('OK:', obj)
    else:
        print('WARNING: Data corruption')
  • 输出显示,第一个对象被验证,第二个对象被认为是 "损坏的",正如预期。

How To Sign and Verify Cryptographic Messages In Your Apps - the output

用简单的字符串或字节比较两个摘要可以在定时攻击中使用,通过传递不同长度的摘要暴露部分或全部密匙。 compare_digest()实现了一个快速但恒定时间的比较函数,以防止定时攻击。

恭喜你!你已经学会了如何实现Python密码。你已经学会了如何使用Python GUI for Delphi Windows App中内置的hmac 库来实现Python加密服务。