Cách nhận tổng kiểm MD5 trong PowerShell


179

Tôi muốn tính toán tổng kiểm MD5 của một số nội dung. Làm cách nào để làm điều này trong PowerShell?


3
"Một số nội dung" là gì? một tập tin? chuỗi?
vcsjones

Câu trả lời:


326

Nếu nội dung là một chuỗi:

$someString = "Hello, World!"
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$utf8 = New-Object -TypeName System.Text.UTF8Encoding
$hash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($someString)))

Nếu nội dung là một tệp:

$someFilePath = "C:\foo.txt"
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($someFilePath)))

Bắt đầu từ PowerShell phiên bản 4, điều này rất dễ thực hiện đối với các tệp nằm ngoài hộp với Get-FileHashlệnh ghép ngắn:

Get-FileHash <filepath> -Algorithm MD5

Điều này chắc chắn là tốt hơn vì nó tránh được các vấn đề mà giải pháp đầu tiên đưa ra như được xác định trong các nhận xét (sử dụng một luồng, đóng nó và hỗ trợ các tệp lớn).


12
Exception calling "ReadAllBytes" with "1" argument(s): "The file is too long. This operation is currently limited to supporting files less than 2 gigabytes in size."Là một người Linux mới biết đến Powershell, tôi rất khó chịu với những cuộc đấu tranh mà tôi đang có một khoản tiền md5, điều này chỉ đơn giản là md5sum file.exttrên Linux.
StockB

Câu trả lời của @StockB Keith dưới đây có lẽ sẽ xử lý việc này tốt hơn. Tôi đồng ý, có một số thiếu sót với powershell.
vcsjones

5
Tôi đã cài đặt vanilla PowerShell không có tiện ích mở rộng, vì vậy tôi đã chia nhỏ và tải xuống một bản sao dòng lệnh md5sum thay thế, hoạt động rất tốt. Tôi muốn những thứ của Microsoft, nhưng tôi không thể.
StockB

23
Phương thức của @StockB vcsjones không được đệm ... = rất cần bộ nhớ cho các tệp lớn. Tôi khuyên bạn nên làm việc với các luồng: $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))Điều này cho phép bạn sử dụng bộ nhớ thấpkhông giới hạn 2GB .
Davor Josipovic

20
@davor giữ luồng mở trong một khoảng thời gian không xác định, vì vậy bạn không thể xóa tệp cho đến khi Powershell bị đóng. $stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)sau $hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))đó$stream.Close()
Joe Amenta

57

Nếu bạn đang sử dụng Tiện ích mở rộng cộng đồng PowerShell, có một lệnh Get-Hash sẽ thực hiện việc này một cách dễ dàng:

C:\PS> "hello world" | Get-Hash -Algorithm MD5


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764

10
Get-Hash đến từ Tiện ích mở rộng cộng đồng PowerShell. Khi bạn không thể hoặc không sử dụng gói, họ đã thêm một lệnh ghép ngắn Get-FileHashtrong vanilla PowerShell 4.0. Vide TechNet .
Tomasz Cudziło

Lưu ý rằng điều này (và có lẽ là hầu hết các giải pháp PS) mã hóa chuỗi dưới dạng UTF-16 (little endian?).
Christian Mann

Liên kết đến Tiện ích mở rộng cộng đồng PowerShell chuyển hướng đến kho lưu trữ CodePlex (CodePlex đã đóng cửa vào năm 2017). Có lẽ thay đổi để một GitHub ? (Là vị trí chính mới trên GitHub?)
Peter Mortensen

16

Đây là hai dòng, chỉ cần thay đổi "xin chào" trong dòng # 2:

PS C:\> [Reflection.Assembly]::LoadWithPartialName("System.Web")
PS C:\> [System.Web.Security.FormsAuthentication]::HashPasswordForStoringInConfigFile("hello", "MD5")

1
Kết quả của điều này không bằng sản lượng tôi nhận được với câu trả lời được chấp nhận. Nó tính toán hàm băm của "xin chào", không phải là một TẬP TIN mà sẽ được xác định bởi bất kỳ đường dẫn nào mà tôi thay thế "xin chào" bằng, đúng không?
RobertG

1
Đúng, nhưng OP đã không yêu cầu một tệp và tôi đã đến đây để tìm giải pháp chuỗi
Chris F Carroll

16

Đây là một chức năng tôi sử dụng để xử lý các đường dẫn tương đối và tuyệt đối:

function md5hash($path)
{
    $fullPath = Resolve-Path $path
    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $file = [System.IO.File]::Open($fullPath,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
    try {
        [System.BitConverter]::ToString($md5.ComputeHash($file))
    } finally {
        $file.Dispose()
    }
}

Cảm ơn @davor ở trên về đề xuất sử dụng Open () thay vì ReadAllBytes () và @ jpmc26 cho đề xuất sử dụng khối cuối cùng.


2
Cách tiếp cận này tốt hơn IMHO so với vcsjones 'và Keith vì nó có thể lấy đầu vào của các tệp lớn hơn 2GB và nó không cần bất kỳ tiện ích mở rộng hoặc PowerShell 4.0 nào.
Chirag Bhatia - chirag64

1
Cuộc Disposegọi nên ở trong một finallykhối.
jpmc26

12

Một lệnh tích hợp khác đã được cài đặt từ lâu trong Windows theo mặc định có từ năm 2003 là Certutil , tất nhiên cũng có thể được gọi từ PowerShell.

CertUtil -hashfile file.foo MD5

(Hãy cẩn thận: MD5 phải có trong tất cả các mũ để có độ bền tối đa)


1
Đây là một lựa chọn tốt khi FipsAlgorithmPolicyđược kích hoạt.
William John Holden

9

Có rất nhiều ví dụ trực tuyến sử dụng ComputeHash (). Thử nghiệm của tôi cho thấy điều này rất chậm khi chạy qua kết nối mạng. Đoạn mã dưới đây chạy nhanh hơn nhiều đối với tôi, tuy nhiên số dặm của bạn có thể thay đổi:

$md5 = [System.Security.Cryptography.MD5]::Create("MD5")
$fd = [System.IO.File]::OpenRead($file)
$buf = New-Object byte[] (1024*1024*8) # 8 MB buffer
while (($read_len = $fd.Read($buf,0,$buf.length)) -eq $buf.length){
    $total += $buf.length
    $md5.TransformBlock($buf,$offset,$buf.length,$buf,$offset)
    Write-Progress -Activity "Hashing File" `
       -Status $file -percentComplete ($total/$fd.length * 100)
}

# Finalize the last read
$md5.TransformFinalBlock($buf, 0, $read_len)
$hash = $md5.Hash

# Convert hash bytes to a hexadecimal formatted string
$hash | foreach { $hash_txt += $_.ToString("x2") }
Write-Host $hash_txt

1
Phương pháp của bạn vượt qua giới hạn 2Gb của ReadAllBytes từ các câu trả lời khác, đó chính xác là những gì tôi cần.
Jay

Backtick trên write-progressdòng làm gì? Cú pháp highlighter dường như không thích nó.
mwfearnley

1
@mwfearnley Backtick cho phép tiếp tục dòng. blog.technet.microsoft.com/heyscriptingguy/2015/06/19/19
cmcginty

6

Trang web này có một ví dụ: Sử dụng Powershell cho MD5 Checksums . Nó sử dụng .NET framework để khởi tạo một thể hiện của thuật toán băm MD5 để tính toán hàm băm.

Đây là mã từ bài viết, kết hợp với nhận xét của Stephen:

param
(
  $file
)

$algo = [System.Security.Cryptography.HashAlgorithm]::Create("MD5")
$stream = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open,
    [System.IO.FileAccess]::Read)

$md5StringBuilder = New-Object System.Text.StringBuilder
$algo.ComputeHash($stream) | % { [void] $md5StringBuilder.Append($_.ToString("x2")) }
$md5StringBuilder.ToString()

$stream.Dispose()

1
Tốt ngoại trừ nó không hoạt động cho các tập tin chỉ đọc! Nó cần $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: Read)
Stephen Connolly

1
Nếu liên kết bao giờ chết, câu trả lời sẽ khá vô dụng. stackoverflow.com/help/how-to-answer
Tôi sẽ cùng với Monica

1
Để đáp lại những gì tôi đoán là downvote của bạn, tôi đã cắt và dán mã từ bài viết ở đây. Tôi đã không làm điều đó năm ngoái, bởi vì tôi cảm thấy đó là đạo văn. Thêm phần thích ứng chỉ đọc của Stephen khiến tôi cảm thấy nó đáng để đăng.
neontapir

@neontapir chỉ để nói: đăng một cái gì đó nguyên văn (hoặc với sự thích nghi) chỉ là đạo văn nếu bạn không thừa nhận nguồn. Bản quyền (về mặt pháp lý hoặc đạo đức) là một vấn đề riêng biệt, nhưng tôi sẽ không có xu hướng lo lắng về điều đó với hầu hết các đoạn mã.
mwfearnley

6

Như đã nêu trong câu trả lời được chấp nhận, Get-FileHashrất dễ sử dụng với các tệp, nhưng cũng có thể sử dụng nó với các chuỗi:

$s = "asdf"
Get-FileHash -InputStream ([System.IO.MemoryStream]::New([System.Text.Encoding]::ASCII.GetBytes($s)))

5

Hiện tại đã có chức năng Get-FileHash rất tiện dụng.

PS C:\> Get-FileHash C:\Users\Andris\Downloads\Contoso8_1_ENT.iso -Algorithm SHA384 | Format-List

Algorithm : SHA384
Hash      : 20AB1C2EE19FC96A7C66E33917D191A24E3CE9DAC99DB7C786ACCE31E559144FEAFC695C58E508E2EBBC9D3C96F21FA3
Path      : C:\Users\Andris\Downloads\Contoso8_1_ENT.iso

Chỉ cần thay đổi SHA384thành MD5.

Ví dụ là từ tài liệu chính thức của PowerShell 5.1 . Các tài liệu có nhiều ví dụ.



3

PowerShell One-Liners (chuỗi để băm)

MD5

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA1

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA256

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA384

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA384CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA512

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA512CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

1

Điều này sẽ trả về hàm băm MD5 cho một tệp trên máy tính từ xa:

Invoke-Command -ComputerName RemoteComputerName -ScriptBlock {
    $fullPath = Resolve-Path 'c:\Program Files\Internet Explorer\iexplore.exe'
    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $file = [System.IO.File]::OpenRead($fullPath)
    $hash = [System.BitConverter]::ToString($md5.ComputeHash($file))
    $hash -replace "-", ""
    $file.Dispose()
}

1

Mẫu cho tùy chọn menu chuột phải là tốt:

[HKEY_CLASSES_ROOT\*\shell\SHA1 PS check\command]
@="C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -NoExit -Command Get-FileHash -Algorithm SHA1 '%1'"

0

Dưới đây là một ví dụ in đẹp cố gắng xác minh dấu vân tay SHA256. Tôi đã tải xuống gpg4win v3.0.3 bằng PowerShell v4 (yêu cầu Get-FileHash).

Tải xuống gói từ https://www.gpg4win.org/doad.html , mở PowerShell, lấy hàm băm từ trang tải xuống và chạy:

cd ${env:USERPROFILE}\Downloads
$file = "gpg4win-3.0.3.exe"

# Set $hash to the hash reference from the download page:
$hash = "477f56212ee60cc74e0c5e5cc526cec52a069abff485c89c2d57d1b4b6a54971"

# If you have an MD5 hash: # $hashAlgo="MD5"
$hashAlgo = "SHA256"

$computed_hash = (Get-FileHash -Algorithm $hashAlgo $file).Hash.ToUpper()
if ($computed_hash.CompareTo($hash.ToUpper()) -eq 0 ) {
    Write-Output "Hash matches for file $file" 
} 
else { 
    Write-Output ("Hash DOES NOT match for file {0}: `nOriginal hash: {1} `nComputed hash: {2}" -f ($file, $hash.ToUpper(), $computed_hash)) 
}

Đầu ra:

Hash matches for file gpg4win-3.0.3.exe

0

Dưới đây là ví dụ một dòng lệnh với cả tính toán tổng kiểm tra chính xác của tệp , giống như bạn vừa tải xuống và so sánh nó với tổng kiểm tra đã xuất bản của bản gốc.

Chẳng hạn, tôi đã viết một ví dụ để tải xuống từ dự án Apache JMeter . Trong trường hợp này, bạn có:

  1. tập tin nhị phân tải về
  2. tổng kiểm tra của bản gốc được xuất bản trong file.md5 dưới dạng một chuỗi ở định dạng:

3a84491f10fb7b147101cf3926c4a855 * apache-jmeter-4.0.zip

Sau đó, sử dụng lệnh PowerShell này, bạn có thể xác minh tính toàn vẹn của tệp đã tải xuống:

PS C:\Distr> (Get-FileHash .\apache-jmeter-4.0.zip -Algorithm MD5).Hash -eq (Get-Content .\apache-jmeter-4.0.zip.md5 | Convert-String -Example "hash path=hash")

Đầu ra:

True

Giải trình:

Toán hạng đầu tiên của -eqtoán tử là kết quả của việc tính toán tổng kiểm tra cho tệp:

(Get-FileHash .\apache-jmeter-4.0.zip -Algorithm MD5).Hash

Toán hạng thứ hai là giá trị tổng kiểm tra được công bố. Trước tiên, chúng tôi nhận nội dung của tệp.m.m5 là một chuỗi và sau đó chúng tôi trích xuất giá trị băm dựa trên định dạng chuỗi:

Get-Content .\apache-jmeter-4.0.zip.md5 | Convert-String -Example "hash path=hash"

Cả filefile.md5 phải nằm trong cùng một thư mục để lệnh này hoạt động.


0

Đây là những gì tôi sử dụng để có được giá trị băm nhất quán:

function New-CrcTable {
    [uint32]$c = $null
    $crcTable = New-Object 'System.Uint32[]' 256

    for ($n = 0; $n -lt 256; $n++) {
        $c = [uint32]$n
        for ($k = 0; $k -lt 8; $k++) {
            if ($c -band 1) {
                $c = (0xEDB88320 -bxor ($c -shr 1))
            }
            else {
                $c = ($c -shr 1)
            }
        }
        $crcTable[$n] = $c
    }

    Write-Output $crcTable
}

function Update-Crc ([uint32]$crc, [byte[]]$buffer, [int]$length, $crcTable) {
    [uint32]$c = $crc

    for ($n = 0; $n -lt $length; $n++) {
        $c = ($crcTable[($c -bxor $buffer[$n]) -band 0xFF]) -bxor ($c -shr 8)
    }

    Write-Output $c
}

function Get-CRC32 {
    <#
        .SYNOPSIS
            Calculate CRC.
        .DESCRIPTION
            This function calculates the CRC of the input data using the CRC32 algorithm.
        .EXAMPLE
            Get-CRC32 $data
        .EXAMPLE
            $data | Get-CRC32
        .NOTES
            C to PowerShell conversion based on code in https://www.w3.org/TR/PNG/#D-CRCAppendix

            Author: Øyvind Kallstad
            Date: 06.02.2017
            Version: 1.0
        .INPUTS
            byte[]
        .OUTPUTS
            uint32
        .LINK
            https://communary.net/
        .LINK
            https://www.w3.org/TR/PNG/#D-CRCAppendix

    #>
    [CmdletBinding()]
    param (
        # Array of Bytes to use for CRC calculation
        [Parameter(Position = 0, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [byte[]]$InputObject
    )

    $dataArray = @()
    $crcTable = New-CrcTable
    foreach ($item  in $InputObject) {
        $dataArray += $item
    }
    $inputLength = $dataArray.Length
    Write-Output ((Update-Crc -crc 0xffffffffL -buffer $dataArray -length $inputLength -crcTable $crcTable) -bxor 0xffffffffL)
}

function GetHash() {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$InputString
    )

    $bytes = [System.Text.Encoding]::UTF8.GetBytes($InputString)
    $hasCode = Get-CRC32 $bytes
    $hex = "{0:x}" -f $hasCode
    return $hex
}

function Get-FolderHash {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$FolderPath
    )

    $FolderContent = New-Object System.Collections.ArrayList
    Get-ChildItem $FolderPath -Recurse | Where-Object {
        if ([System.IO.File]::Exists($_)) {
            $FolderContent.AddRange([System.IO.File]::ReadAllBytes($_)) | Out-Null
        }
    }

    $hasCode = Get-CRC32 $FolderContent
    $hex = "{0:x}" -f $hasCode
    return $hex.Substring(0, 8).ToLower()
}

Bạn đã sao chép mã PowerShell từ đâu? https://cransary.net/ ?
Peter Mortensen

0

Đây là đoạn mã mà tôi đang sử dụng để lấy MD5 cho một chuỗi đã cho:

$text = "text goes here..."
$md5  = [Security.Cryptography.MD5CryptoServiceProvider]::new()
$utf8 = [Text.UTF8Encoding]::UTF8
$bytes= $md5.ComputeHash($utf8.GetBytes($text))
$hash = [string]::Concat($bytes.foreach{$_.ToString("x2")}) 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.