Портативное приложение для вычисления одного (выбираемого) хэша для выбранного файла?

Как ни странно, но я не могу найти портативное приложение для вычисления одного отдельного хэша (типа, типа SHA256, SHA512, Whirlpool, SHA3?) для выбранного файла! Это все, что я нашел:

  1. RapidCRCUnicodePortable — у него очень недружественное поведение. Что я вижу? Я открываю это приложение, нажимаю кнопку «Открыть файлы» и выбираю свой файл. Я вижу имя файла в списке и странное сообщение справа: «Хэш не найден». Хорошо, я нажимаю кнопку «Файл SHA256» и вижу это сообщение: «Сначала вам нужно рассчитать контрольные суммы sha256. Нажмите OK, чтобы сделать это сейчас». Я нажимаю ОК. Имя файла теперь продублировано в списке с тем же текстом «Хэш не найден» справа, но теперь — поздравляю! — Наконец-то я могу скопировать найденный хэш SHA256 в буфер обмена. И что странно, это приложение вылетает в моей системе, когда я удаляю файлы из списка. Я не могу понять, как эта ошибка может существовать. Это заставляет меня думать, что это программное обеспечение нестабильно.
  2. ChecksumControlPortable предназначен только для создания файлов SFV/MD5. И, кстати, он даже не может выбрать отдельный файл через проводник, он использует интерфейс перетаскивания, но я ненавижу этот тип интерфейса. Я никогда не использую перетаскивание.
  3. HashGenerator тратит много времени и циклов ЦП на вычисление всех типов хэшей одновременно. Это делает это приложение чрезвычайно неудобным для пользователя при работе с огромными файлами.

Есть Multihasher , но он не поддерживает некоторые важные типы хэшей, такие как SHA-3 и Whirlpool.
В HashTab есть все, что мне нужно, но... как жаль! Это устанавливаемая dll для системной интеграции без портативного приложения.
На самом деле, я немного в шоке от этой ситуации. Я никогда не ожидал, что не смогу найти подходящее программное обеспечение для такой распространенной проблемы.

WinMD5 вычисляет только MD5.
HashMyFiles вычисляет только CRC32, MD5 и SHA1 .
Для Windows? Если да, может ли это потребовать .NET? Какие хэши он должен хотя бы поддерживать?
@ wb9688: "Может ли это потребовать .NET?" Нет. Зависимость от .NET означает, что пользователь будет вынужден установить фреймворк перед использованием приложения. Это не всегда возможно. И, насколько я понимаю, нет портативного .NET . «Какие хэши он должен хотя бы поддерживать?» SHA-2 требуется, я полагаю. Я думаю, было бы неплохо иметь SHA-3 и Whirlpool.

Ответы (2)

Некоторое время назад я сделал для себя небольшую утилиту командной строки. Загрузите его, если вы найдете его полезным.

Программа никогда ранее не публиковалась (и не подписывалась), поэтому может быть определена как вредоносное ПО (по крайней мере , так говорит VirusTotal ).

Он написан на Python 3. Это источник:

# -*- coding: utf-8 -*-

import os.path
import pprint
import time
import json
import sys
import re
import hashlib
import zlib
import sha3 # This adds sha_3 functions to the hashlib module, install with 'pip install pysha3'

class crc32(object):
    name = 'crc32'
    digest_size = 4
    block_size = 1

    def __init__(self, arg=''):
        arg = arg.encode()
        self.__digest = 0
        self.update(arg)

    def copy(self):
        copy = super(self.__class__, self).__new__(__class__)
        copy.__digest = self.__digest
        return copy

    def digest(self):
        return self.__digest

    def hexdigest(self):
        return '{:08x}'.format(self.__digest)

    def update(self, arg):
        self.__digest = zlib.crc32(arg, self.__digest) & 0xffffffff

hashlib.crc32 = crc32

def md4File(path, block_size=256*128):
    md4 = hashlib.new("md4")
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            md4.update(chunk)
    return md4.hexdigest()

def md5File(path, block_size=256*128):
    md5 = hashlib.md5()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            md5.update(chunk)
    return md5.hexdigest()

def sha1File(path, block_size=256*128):
    sha1 = hashlib.sha1()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha1.update(chunk)
    return sha1.hexdigest()

def crc32File(path, block_size=256*128):
    crc32 = hashlib.crc32()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            crc32.update(chunk)
    return crc32.hexdigest()

def sha224File(path, block_size=256*128):
    sha224 = hashlib.sha224()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha224.update(chunk)
    return sha224.hexdigest()

def sha256File(path, block_size=256*128):
    sha256 = hashlib.sha224()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha256.update(chunk)
    return sha256.hexdigest()

def sha384File(path, block_size=256*128):
    sha384 = hashlib.sha384()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha384.update(chunk)
    return sha384.hexdigest()

def sha512File(path, block_size=256*128):
    sha512 = hashlib.sha512()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha512.update(chunk)
    return sha512.hexdigest()

def ripemd160File(path, block_size=256*128):
    rmd160 = hashlib.new("ripemd160")
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            rmd160.update(chunk)
    return rmd160.hexdigest()

def dsaFile(path, block_size=256*128):
    dsa = hashlib.new("dsa")
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            dsa.update(chunk)
    return dsa.hexdigest()

def whirlpoolFile(path, block_size=256*128):
    wrp = hashlib.new("whirlpool")
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            wrp.update(chunk)
    return wrp.hexdigest()

def sha3_224File(path, block_size=256*128):
    sha3_224 = hashlib.sha3_224()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha3_224.update(chunk)
    return sha3_224.hexdigest()

def sha3_256File(path, block_size=256*128):
    sha3_256 = hashlib.sha3_256()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha3_256.update(chunk)
    return sha3_256.hexdigest()

def sha3_384File(path, block_size=256*128):
    sha3_384 = hashlib.sha3_384()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha3_384.update(chunk)
    return sha3_384.hexdigest()

def sha3_512File(path, block_size=256*128):
    sha3_512 = hashlib.sha3_512()
    with open(path,'rb') as f: 
        for chunk in iter(lambda: f.read(block_size), b''): 
            sha3_512.update(chunk)
    return sha3_512.hexdigest()


def getJson(results):
    jdump = json.dumps(results, ensure_ascii=False)
    return re.sub('[^\s!-~]', '?', jdump)

def getString(results):
    text = ""
    for i in results:
        text += "File: " + i + "\n"

        for j in results[i]:
            text += j[0] + ": " + j[1] + "\n"

        text += "\n"

    return re.sub('[^\s!-~]', '?', text[:-2])


def showHelp(name):
    nameT = name.replace("\\","/").split("/")[-1]
    helpText = """
//////////////////////
/ File/Folder hasher /
//////////////////////

Usage: %s  path [-md4]       [-md5]
            [-sha1]      [-crc32]
            [-sha224]    [-sha256]
            [-sha384]    [-sha512]
            [-ripemd160] [-whirlpool]
            [-sha3_224]  [-sha3_256]
            [-sha3_384]  [-sha3_512]

            [-all]
            [-file <file name>]
            [-json]

Options:
    path    Path to file or directory to hash

    -all    Use all hash algorithms.
    -file   Save hash report to a text file
    -json   Format output in json

Hash algorithm options:
    -md4    
    -md5
    -sha1
    -crc32
    -sha224
    -sha256
    -sha384
    -sha512
    -ripemd160
    -whirlpool
    -sha3_224
    -sha3_256
    -sha3_384
    -sha3_512
"""
    print(helpText % nameT)

def main():
    args = sys.argv

    if len(args) < 3:
        print("Not enough arguments!")
        showHelp(args[0])
        sys.exit(1)

    allowed = [
    "-file",
    "-all",
    "-md4",
    "-md5",
    "-sha1",
    "-crc32",
    "-sha224",
    "-sha256",
    "-sha384",
    "-sha512",
    "-ripemd160",
    "-whirlpool",
    "-json",
    "-raw",
    "-sha3_224",
    "-sha3_256",
    "-sha3_384",
    "-sha3_512",
    ]

    hashes = [
    "-md4",
    "-md5",
    "-sha1",
    "-crc32",
    "-sha224",
    "-sha256",
    "-sha384",
    "-sha512",
    "-ripemd160",
    "-whirlpool",
    "-sha3_224",
    "-sha3_256",
    "-sha3_384",
    "-sha3_512",
    ]

    dataContain = [
    "-file",
    ]

    b = 2
    for i in args[b:]:
        if args.count(i) > 1:
            print("Repeating options: " + i)
            showHelp(args[0])
            sys.exit(1)

        if not i in allowed and args[b-1] not in dataContain:
            print("Invalid option: " + i)
            print(args[b+1])
            showHelp(args[0])
            sys.exit(1)

        b += 1
    else:
        if args[-1] in dataContain:
            print("'%s' option must have a file path next to it." % i)
            showHelp(args[0])
            sys.exit(1) 

    for i in args[2:]:
        if i in hashes + ["-all"]:
            break

    else:
        print("No hashes specified.")
        showHelp(args[0])
        sys.exit(1)         

    collisions = {
    "-all" : ["-md4", "-md5", "-sha1", 
              "-crc32", "-sha224", "-sha256", 
              "-sha384", "-sha512", "-ripemd160", 
              "-whirlpool", "-sha3_224", "-sha3_256", 
              "-sha3_384", "-sha3_512",]
    }

    for i in collisions:
        if i in args:
            for j in collisions[i]:
                if j in args:
                    print("Colliding options. (" + i + " and " + j + ")")
                    showHelp(args[0])
                    sys.exit(1)

    fileName = args[1]
    fileNameT = fileName.replace("\\", "/").split("/")[-1]
    if os.path.isfile(fileName):
        ftype = "file"

    elif os.path.isdir(fileName):
        ftype = "directory"

    else:
        print("File or directory does not exits or you don't have permission to read it.")
        showHelp(args[0])
        sys.exit(1) 

    funcTable = {
    "-md4"        : ("MD4", md4File),
    "-md5"        : ("MD5", md5File),
    "-sha1"       : ("SHA1", sha1File),
    "-crc32"      : ("CRC32", crc32File),
    "-sha224"     : ("SHA224", sha224File),
    "-sha256"     : ("SHA256", sha256File),
    "-sha384"     : ("SHA384", sha384File),
    "-sha512"     : ("SHA512", sha512File),
    "-ripemd160"  : ("Ripemd160", ripemd160File),
    "-whirlpool"  : ("Whirlpool", whirlpoolFile),
    "-sha3_224"   : ("SHA3-224", sha3_224File),
    "-sha3_256"   : ("SHA3-256", sha3_256File),
    "-sha3_384"   : ("SHA3-384", sha3_384File),
    "-sha3_512"   : ("SHA3-512", sha3_512File),
    }
    funcList = []

    if "-all" in args:
        for i in hashes:
            funcList.append(funcTable[i])
    else:
        for i in hashes:
            if i in args:
                funcList.append(funcTable[i])

    try:
        if ftype == "file":
            print("Hashing...\n")

            results = {}
            results[fileNameT] = []
            st = time.time()
            try:
                for function in funcList:
                    hash = function[1](fileName)
                    results[fileNameT].append([function[0], hash])

            except KeyboardInterrupt:
                print("Hashing canceled.")
                sys.exit(2)

            except PermissionError:
                print("You don't have permission to access the file.")
                showHelp(args[0])
                sys.exit(2)         

            et = time.time()

            if "-json" in args:
                strResults = getJson(results)

            elif "-raw" in args:
                strResults = results

            else:
                strResults = getString(results)

            if "-file" in args:
                print("Writing file...")
                f = open(args[args.index("-file") + 1], "w")
                f.write(strResults)
                f.close()
                print("File saved sucessfully in %s seconds." % str("{0:.2f}".format(et-st)))

            else:
                print(strResults)
                print("\nCalculated in %s seconds." % str("{0:.2f}".format(et-st)))

            sys.exit(0)

        else:
            filenum = 0
            print("Scanning files...")

            st = time.time()
            try:
                for subdir, dirs, files in os.walk(fileName):
                    for file in files:
                        filenum += 1        

            except KeyboardInterrupt:
                print("Files not scanned. Progress cannot be tracked.")
                filenum = -1

            if filenum == 0:
                print("Directory is empty or you don't have permission to read it.")
                showHelp(args[0])
                sys.exit(1)

            print("Number of files: " + str(filenum))
            print("Hashing...\n")

            results = {}

            onfile = 1
            passed = 0
            try:
                if filenum == -1:
                    print(" |     Hashing...     | ???%", end="\r")

                for subdir, dirs, files in os.walk(fileName):
                    for file in files:
                        results[os.path.join(subdir, file)] = []

                        if filenum != -1:
                            perc = onfile/filenum
                            percnum = "{0:.2f}".format(perc*100)
                            toprint = " |" + ("#" * int((20*perc))) + " " * int(20-int(20*perc))  + "| " + percnum + "%"

                            print(toprint, end="\r")

                        for function in funcList:
                            try:
                                try:
                                    hash = function[1](os.path.join(subdir, file))
                                    results[os.path.join(subdir, file)].append([function[0], hash])

                                except PermissionError:
                                    results[os.path.join(subdir, file)].append(["Error", "Access denied"])
                                    passed += 1

                                except FileNotFoundError:
                                    results[os.path.join(subdir, file)].append(["Error", "File not found"])
                                    passed += 1
                            except Exception as e:
                                results[os.path.join(subdir, file)].append(["Error", str(e)])
                                passed += 1

                        onfile += 1

                else:
                    print(" |####################| 100%       \n")



            except KeyboardInterrupt:
                print("Hashing canceled.                 ")
                sys.exit(2)

            et = time.time()
            print("Passed %s files" % str(passed))

            if "-json" in args:
                strResults = getJson(results)

            elif "-raw" in args:
                strResults = results

            else:
                strResults = getString(results)

            if "-file" in args:
                print("Writing file...")
                f = open(args[args.index("-file") + 1], "wb")
                f.write(strResults.encode())
                f.close()
                print("\nFile saved sucessfully in %s seconds." % str("{0:.2f}".format(et-st)))

            else:
                print(strResults)
                print("\nCalculated in %s seconds." % str("{0:.2f}".format(et-st)))

            sys.exit(0)

    except MemoryError:
        print("Maximum memory reached. Please consider using an x64 version of the program and upgrading your RAM.\n")

if __name__ == "__main__":
    main()

Он может хешировать файл или папку с помощью следующих алгоритмов:

  • md4

  • мд5

  • Ша1
  • crc32
  • ша224
  • ша256
  • ша384
  • ша512
  • спелый160
  • водоворот
  • sha3_224
  • sha3_256
  • sha3_384
  • sha3_512

  • Вы также можете сохранить хешированные значения в файле или отформатировать их с помощью json для упрощения анализа.

Хорошая вещь в том, что вы можете легко создать файл .bat для автоматизации.

Если вам действительно нужна эта программа, но вы доверяете своему антивирусу больше, чем мне, скомпилируйте приведенный выше исходник с помощью pyinstaller .

  1. Установите Python 3 (следите за 32-битными/64-битными версиями)
  2. Установите пиинсталлятор:pip install pyinstaller
  3. Сохраните исходный код в файл с именем hasher.py.
  4. Запустите команду: pyinstaller hasher.py4.5 Необязательно запустите: pyinstaller hasher.py --onefileесли вы хотите, чтобы исполняемый файл был только одним
  5. Выгода

Обратите внимание, что совместимость скомпилированного exe не проверялась, потому что у меня нет времени.

Щелкните меня для загрузки.

rhash — это инструмент командной строки, который может вычислять отдельные хэши.

Вы можете использовать мой сценарий shellex.bat, чтобы добавить запись в контекстное меню проводника, которая показывает хэш в окне консоли.

Например, это добавит команду «CRC32» в каждый файл (вставьте ее и выполните из пакетного файла):

call shellex * CRC32 ""%~d0\PortableApps\ConEmu\ConEmu.exe" /cmd "%PROGRAMFILES%\Rhash\rhash.exe" -C --simple ""%%%%1""" 

Еще один вариант использования certuil — здесь .

Кстати, для небольших файлов я предпочитаю HashMyFiles из-за более удобного графического интерфейса.