【问题标题】:Calculate and add hash to a file in python在python中计算并将哈希添加到文件中
【发布时间】:2016-03-11 12:20:05
【问题描述】:

检查文件是否被修改的一种方法是计算和存储文件的哈希(或校验和)。然后在任何时候都可以重新计算哈希值并与存储的值进行比较。

我想知道是否有一种方法可以将文件的哈希值存储在文件本身中?我在考虑文本文件。

计算哈希的算法应该是迭代的,并且考虑到哈希将被添加到正在计算哈希的文件中......有意义吗?有什么可用的吗?

谢谢!

编辑: https://security.stackexchange.com/questions/3851/can-a-file-contain-its-md5sum-inside-it

【问题讨论】:

  • 不,这没有意义 - 从文件中单独存储校验和。
  • 如果你将哈希值存储在文件中,文件的哈希值将会改变。
  • 毫无意义,如果你用文件传输校验和,现在任何人都可以修改你的校验和
  • 这与HMAC 有何不同。你用你的私钥散列你的消息。然后,当您稍后查看该消息时,您尝试再次对其进行哈希处理,如果哈希值不大,您就知道有人更改了某些内容。这是一个诚信问题,而不是保密问题。含义:我认为这是一个完全合理的问题。
  • @KlausD。合理的逻辑,但 NTFS 有更多的魔力......

标签: python hash checksum


【解决方案1】:
from Crypto.Hash import HMAC
secret_key = "Don't tell anyone"
h = HMAC.new(secret_key)
text = "whatever you want in the file"
## or: text = open("your_file_without_hash_yet").read()
h.update(text)
with open("file_with_hash") as fh:
    fh.write(text)
    fh.write(h.hexdigest())

现在,正如一些人试图指出的那样,尽管他们看起来很困惑——你需要记住,这个文件的末尾有哈希值,并且哈希值本身不是被哈希值的一部分。因此,当您想要检查文件时,您可以执行以下操作:

end_len = len(h.hex_digest())
all_text = open("file_with_hash").read()
text, expected_hmac = all_text[:end_len], all_text[end_len:]
h = HMAC.new(secret_key)
h.update(text)
if h.hexdigest() != expected_hmac:
    raise "Somebody messed with your file!"

应该清楚的是,这个单独并不能确保您的文件没有被更改;典型的用例是加密您的文件,但采用明文的哈希值。这样,如果有人更改哈希(在文件末尾)或尝试更改消息中的任何字符(加密部分),事情就会不匹配,您就会知道某些事情发生了变化。

恶意行为者将无法更改文件并修复哈希以匹配,因为他们需要更改一些数据,然后使用您的私钥重新哈希所有内容。只要没有人知道您的私钥,他们就不会知道如何重新创建正确的哈希。

【讨论】:

    【解决方案2】:

    这是一个有趣的问题。如果您采用适当的约定来散列和验证文件的完整性,您就可以做到这一点。假设你有这个文件,即main.py:

    #!/usr/bin/env python
    # encoding: utf-8
    print "hello world"
    

    现在,您可以将 SHA-1 哈希作为注释附加到 python 文件:

    (printf '#'; cat main.py | sha1sum) >> main.py
    

    更新main.py:

    #!/usr/bin/env python
    # encoding: utf-8
    print "hello world"
    #30e3b19d4815ff5b5eca3a754d438dceab9e8814  -
    

    因此,要验证文件是否被修改,您可以在 Bash 中执行此操作:

    if [ "$(printf '#';head -n-1 main.py | sha1sum)" == "$(tail -n1 main.py)" ]
    then
        echo "Unmodified"
    else 
        echo "Modified"
    fi
    

    当然,有人可能会试图通过手动更改哈希字符串来欺骗您。为了阻止这些坏人,您可以通过在将哈希添加到最后一行之前使用 秘密字符串 修改文件来改进系统。

    改进版

    在最后一行添加哈希,包括您的秘密字符串:

    (printf '#';cat main.py;echo 'MyUltraSecretTemperString12345') | sha1sum >> main.py
    

    用于检查文件是否被修改:

    if [ "$(printf '#';(head -n-1 main.py; echo 'MyUltraSecretTemperString12345') | sha1sum)" == "$(tail -n1 main.py)" ]
    then
        echo "Unmodified"
    else 
        echo "Modified"
    fi
    

    使用这个改进的版本,坏人只有在他们首先找到你的超级密钥时才能欺骗你。

    编辑:这是keyed-hash message authentication code (HMAC) 的粗略实现。

    【讨论】:

    • 你的建议和只使用 HMAC 有区别吗?
    • @dwanderson,事实上我不知道 HMAC 方法。看来我的答案以外壳方式处理相同的方法。但很高兴知道有一种更复杂的方法来处理该任务。
    • 令人印象深刻的是,您在几分钟内就想出了行业标准!扎实的工作!
    • 不幸的是,这不是我头脑中的想法 =(。我只记得 JSON 网络令牌的签名方式并复制了总体思路。
    • 嗯,有道理。是的,这是签署文件的一种完全正常的方式,我不确定为什么这么多原始评论者对为什么有人要这样做感到困惑。
    【解决方案3】:

    虽然这看起来是个奇怪的想法,但它可能是 Windows NTFS 文件系统的一个很少使用但非常强大的属性的应用程序:File Streams。

    它允许在一个文件中添加许多流而不改变默认流的内容。例如:

    echo foo > foo.text
    echo bar > foo.text:alt
    type foo.text
    =>   foo
    more < foo.text:alt
    =>   bar
    

    但列出目录时,只能看到一个文件:foo.txt

    因此,在您的用例中,您可以将主流的哈希写入名为hash 的流中,然后将hash 流的内容与主流的哈希进行比较。

    只是备注:由于我不知道的原因,type foo.text:alt 生成以下错误:

    “文件名、目录名或卷标语法不正确。”

    这就是为什么我的示例按照 MSDN 上的 Using streams page 中的建议使用 more &lt;

    因此,假设您有一个 myhash 函数可以提供文件的哈希值(您可以使用 hashlib 模块轻松构建一个):

    def myhash(filename):
        # compute the hash of the file
        ...
        return hash_string
    

    你可以这样做:

    def store_hash(filename):
        hash_string = myhash(filename)
        with open(filename + ":hash") as fd:
            fd.write(hash_string)
    
    def compare_hash(filename):
            hash_string = myhash(filename)
            with open(filename + ":hash") as fd:
                orig = fd.read()
            return (hash_string == orig)
    

    【讨论】:

    • 这与帮助 OP 在 Python 中实现这一点有什么关系?
    • @dwanderson:你是对的。我首先回答了一般信息。我现在用一些 Python 代码更新了我的帖子。
    • OP 明确要求将哈希值存储在文件本身中,这是一个有效且合理的请求,尽管问题上有 cmets;您的解决方案没有考虑到这一点,并且您没有帮助提供散列函数,这似乎是原始问题的很大一部分。 OP想知道“我可以在文件之后存储哈希”(您没有解决这个问题)并且“哈希应该是迭代的”意味着“我使用什么哈希,或者如何使用?” (你假设他们已经有一个哈希函数)。
    • @dwanderson:我已经解释过备用流仍包含在文件中。当您使用copy src dest 复制文件时,您将复制所有流。并且 OP 并没有要求存储散列 after 文件,而是 in 文件。而标准模块hashlib 提供了足够的哈希值。
    • 关于流媒体的公平点 - 我对 Windows 的东西感到困惑,所以我也没有关注。我想我会在答案中提到hashlib,因为 OP 似乎没有意识到并且正在征求意见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-06
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2011-10-24
    • 1970-01-01
    相关资源
    最近更新 更多