internal/functions/Get-PasswordHash.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
function Get-PasswordHash {
    <#
    .SYNOPSIS
    Generates a password hash for SQL Server login
 
    .DESCRIPTION
    Generates a hash string based on the plaintext or securestring password and a SQL Server version. Salt is optional
 
    .PARAMETER Password
    Either plain text or Securestring password
 
    .PARAMETER SqlMajorVersion
    Major version of the SQL Server. Defines the hash algorithm.
 
    .PARAMETER byteSalt
    Optional. Inserts custom salt into the hash instead of randomly generating new salt
 
    .NOTES
    Tags: Login, Internal
    Author: Kirill Kravtsov (@nvarscar)
    dbatools PowerShell module (https://dbatools.io, clemaire@gmail.com)
    Copyright (C) 2016 Chrissy LeMaire
    License: GNU GPL v3 https://opensource.org/licenses/GPL-3.0
 
    .EXAMPLE
    Get-PasswordHash $securePassword 11
 
    Generates password hash for SQL 2012
 
    .EXAMPLE
    Get-PasswordHash $securePassword 9 $byte
 
    Generates password hash for SQL 2005 using custom salt from the $byte variable
 
#>

    param (
        [object]$Password,
        $SqlMajorVersion,
        [byte[]]$byteSalt
    )
    #Choose hash algorithm
    if ($SqlMajorVersion -lt 11) {
        $algorithm = 'SHA1'
        $hashVersion = '0100'
    }
    else {
        $algorithm = 'SHA512'
        $hashVersion = '0200'
    }

    #Generate salt
    if (!$byteSalt) {
        0 .. 3 | ForEach-Object { $byteSalt += Get-Random -Minimum 0 -Maximum 255 }
    }

    #Convert salt to a hex string
    [string]$stringSalt = ""
    $byteSalt | ForEach-Object { $stringSalt += ("{0:X}" -f $_).PadLeft(2, "0") }

    #Extract password
    if ($Password.GetType().Name -eq 'SecureString') {
        $cred = New-Object System.Management.Automation.PSCredential -ArgumentList 'foo', $Password
        $plainPassword = $cred.GetNetworkCredential().Password
    }
    else {
        $plainPassword = $Password
    }
    #Get byte representation of the password string
    $enc = [system.Text.Encoding]::Unicode
    $data = $enc.GetBytes($plainPassword)
    #Run hash algorithm
    $hash = [Security.Cryptography.HashAlgorithm]::Create($algorithm)
    $bytes = $hash.ComputeHash($data + $byteSalt)
    #Construct hex string
    $hashString = "0x$hashVersion$stringSalt"
    $bytes | ForEach-Object { $hashString += ("{0:X2}" -f $_).PadLeft(2, "0") }
    #Add UPPERCASE hash for SQL 2000 and lower
    if ($SqlMajorVersion -lt 9) {
        $data = $enc.GetBytes($plainPassword.ToUpper())
        $bytes = $hash.ComputeHash($data + $byteSalt)
        $bytes | ForEach-Object { $hashString += ("{0:X2}" -f $_).PadLeft(2, "0") }
    }
    return $hashString
}