For an API I need to provide secured information hashed with the HMAC SHA256 protocol. I would like to prepare all my API requests in a stored procedure in an Azure SQL DB, so the hashing needs to take place in SQL. I'm not married to that idea, if there are better ways I can be flexible.
Currently I have the issue that I don't fully understand how different ways of creating the hash, can lead to different outcomes. For instance;
Linux CMD with OpenSSL
~$ echo "message" | openssl dgst -sha256 -hmac "key"
(stdin)=
62b5378a72e18e8b220382be8a4fce0a341ab06afa6367fe664219713e11bb4d
PowerShell
$message = 'message'
$secret = 'key'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)
echo $signature
bp7ym3X//Ft6uuUn1Y/a2y/kLnIZARl2kXNDBl9Y7Uo=
Online tool
https://www.freeformatter.com/hmac-generator.html#ad-output
6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a
My scalar function
Got the function from https://gist.github.com/rmalayter/3130462
declare #query nvarchar(4000),
#secret nvarchar(500);
set #query = 'message'
set #secret = 'key'
select dbo.fn_HMAC('SHA2_256',cast(#query as varbinary(max)), CAST(#secret as varbinary(max)))
0x93552E8AB930FFCEE9E158A7EA5926A4F36025A1A0ED538763B26AF74147D299
So these 4 methods return 4 different Hashes. I know I need the Has as returned by OpenSSL ( first example ).
can you maybe help me understand why these options return different hashes and how to obtain the hash as generated by OpenSSL in Linux CMD?
Got it! HABO was right it did have to do with an NVARCHAR variable in my script. Once replaced with a VARCHAR it worked!!!
Related
Im trying to pass a secure string to an odbc connection object to save me from passing a plain password over a network but cant quite figure it out. See the current iteration of my script below.
$encryptedPassword = Get-Content "<encrypted password.txt>"
$runPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((ConvertTo-SecureString $encryptedPassword)))
$Db2Connection = new-object system.data.odbc.odbcconnection
$Db2Connection.connectionstring = "DSN=<dsn>;Userid=<user>;Password=$runPassword"
$Db2Connection.open()
$SqlQuery = #"
SELECT *
FROM <database>.<table>
"#
$SqlCmd = New-Object system.Data.Odbc.OdbcCommand($SqlQuery,$Db2Connection)
$DataAdapter = New-Object system.Data.Odbc.OdbcDataAdapter($SqlCmd)
$DataTable = New-Object system.Data.datatable
$RowCount = $DataAdapter.fill($DataTable)
$DataAdapter = new-object System.Data.odbc.odbcDataAdapter($SqlCmd)
$DataSet = new-object System.Data.DataSet
$DataAdapter.Fill($DataSet)
$result = $DataSet.Tables[0].Rows[4]
$result
As you can see, while i have encryption at rest the credentials will be handled in clear text using the following.
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((ConvertTo-SecureString $encryptedPassword)))
Any thoughts or recommendations would be appreciated
As you are using an IBM-supplied Db2-driver, it is the Db2-driver itself that handles encrypting the password before transmission.
The Db2-driver does this encrypting transparently to the application, and the application gives the plain-text password to the Db2-driver which encrypts is before transmission. The Db2-server platform (Z/OS, i-series, Linux/Unix/Windows) determines the configuration details for encrypted passwords.
So the application cannot supply an already-encrpyted password to Db2-driver.
Such transparent password-encryption requires correct configuration of the Db2-server authentication setup, and a suitable (meaning: recent and patch-maintained) Db2-driver at the workstations. Db2-clients also support data-encryption in transit in addition to password encryption, but that is a different matter.
As part of the connection attempt, the Db2-driver will obtain from the Db2-server the names of available encryption algorithms the Db2-server can support, and the Db2-client chooses (by default) the most secure algorithm that it can perform that is also available on the Db2-server. You can influence this choice by further configuration as documented in the Db2-Knowledge-Centre.
You can also write your own security-related plugins, if you have special requirements.
I am trying to create a jwt token using a pfx which,I have stored in Octopus library. For this I have to create an object of X509Certificate2, which takes certificate path and password as input. Can someone please suggest a way to do this using powershell?
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certpath,'password')
I have been through some documents as per how to access certificate variables in octopus but how can I use them to create an object of X509Certificate2.
https://octopus.com/docs/deployment-process/variables/certificate-variables
After going through Microsoft and Octopus documentation I have managed to get it to work. Octopus store the certificate as a base64 encoded string in a variable named as Cert.Pfx and constructor of X509Certificate2 takes a byte array as a first parameter. So as a first step I just needed to convert the base64 encoded string to byte array.
$certbytearray=[System.Convert]::FromBase64String($OctopusParameters["Cert.Pfx"])
$CertPassKey="password"
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certbytearray,$CertPassKey)
#Biplab Thanks for posting your solution; it saved me a lot of headache! I had a slightly different situation without a password and I found that the X509Certificate2 constructor interpreted the byte array as a file name when I tried to call without the password even though the documentation indicates it should accept just a byte array.
I got it to work without the password by doing an import instead.
$certbytearray=[System.Convert]::FromBase64String($OctopusParameters["mycert.Pfx"])
$mycert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$mycert.import($certbytearray)
write-host $mycert.ThumbPrint
if ($mycert.HasPrivateKey)
{ write-host "has private key"}
I'm trying to set up a TURN server for a project using Coturn but am finding that documentation is sketchy at best...
I realise that there is a turnadmin tool that will do this for you, but I would greatly prefer to just run queries on my database directly. This is an app with potentially many users and their shared keys (hmackey in turnusers_lt) are subject to change (in order to not share passwords with the app the app uses a 'fake' password which is a hash of certain volatile user parameters that aren't so secret).
I can gather from the scant docs that the hmackey is computed using the realm, username and password:
$ turnadmin -k -u myusername -r my.realm.org -p my-password
> e.g. 0x7a69b0e2b747a4560045f79d171b78c0
Given that my code will know these three parameters, how do I build the hmac hash? E.g. in PHP I have
string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] )
$algo here should be SHA1, but what values would go into $data (e.g. concat of user/pass) and $key (e.g. realm)?
There's also a turn_secret table listing a 'value' for a realm, I was guessing this should be used as the $key in the above example, but adding and modifying the keys still give the same result when I call turnadmin.
Essentially, what I want to do is (pseudo-code):
// user registers
// pseudo-code, this is of course computed using php's password_hash function
$hashed_pw = hash($pw);
$db->query('insert into usertable (name, pass) values ($name, $hashed_pw)');
// this is implemented somewhere...
$coturn_pw = get_secret_hash($name);
// this needs implementing...
$HAMC = calc_hmac($name, $coturn_pw, 'my.realm.com');
$turndb->query('insert into turnusers_lt values (...)');
// on update, delete also update turnusers_lt
...and then in the client, I should now be able to connect to the TURN server using $name and $coturn_pw as credentials for my.realm.com.
Or am I over-thinking this and should I just use a generic user for my app, hardcode the password and let Coturn figure out who is talking to who?
How to build the HMAC key is described in RFC 5389:
key = MD5(username ":" realm ":" SASLprep(password))
where MD5 is defined in RFC 1321 and SASLprep() is defined in RFC 4013
The only table you need to update is turnusers_lt. The turn_secret table and SHA1 algorithm is used for generating time-limited credentials.
INSERT INTO turnusers_lt (realm, name, hmackey) VALUES (:realm, :username, :key);
And of course, use prepared statements rather than building the SQL string manually.
OrangeDog answer is correct.
With node.js:
const crypto= require("crypto");
const username= "foo";
const realm= "here";
const password= "secret";
const hmac = crypto
.createHash("md5")
.update(`${username}:${realm}:${password}`)
.digest("hex")
;
I'm new to Powershell, and I'm trying to do a secure LDAP query using PKI authentication. I'm getting stuck on how to set the certificate and key. Based on Googling/research, I have some of the basics, e.g.:
$connection = new-object System.DirectoryServices.Protocols.LDAPConnection('$domainName:$portNum')
[string[] $get] = "$attribute1", "$attribute2", "attribute3"
$request = new-object System.DirectoryServices.Protocol.SearchRequest("$targetOu", "$filter", "subtree", $get)
$response = new-object $connection.SendRequest($request)
Like I said, I'm getting stuck on how to set/send the certificate and key. I thought I could do $connection.ClientCertificates = $path, but that property is read-only. I also thought I had to do something with $System.Net.NetworkCredential, but I'm not sure if the cert and key actually correspond to username and password. I referred to a Perl script that did an LDAP query and used PKI, and you could do:
clientcert => '/path/to/cert.pem'
clientkey => '/path/to/key.pem'
What's the equivalent for Powershell? Do I have to do something with System.Security.Cryptography.X509Certificates.X509Certificate?
Any help would be appreciated!
$connection.ClientCertificates.Add($cert)
the $cert must be X509Certificate class
and get certificates from store using
$allPersonalCerts = #( Get-ChildItem -Path 'Cert:\CurrentUser\my' )
It returns array of X509Certificate objects (or X509Certificate2 which is child class for X509Certificate )
NB: When doing PowerShell programming, you can always search for help by googling C# or VB.net solutions. This is .Net and examples on .net-oriented languages just differ on syntax
I have some code that I use to connect to a web server that we own. The server has a self signed certificate. I am currently connecting with the trust any cert
[System.Net.ServicePointManager]::ServerCertificateValidationCallback {$true}.
How can I change this so that I can either test the remote server with custom code or against a cert in my local store? For example can I change the code above to
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$customValidator}
What I would like to do is, instead of trusting any/all certs, I would like to trust it only if it matches with the public key cer file I have or I would like to test the certificate using custom code. The thing I am not very clear on is how to handle the custom verification and at what point in the code. Do I need to write an entire class to handle custom SSL validation or is there a better way to do this?
$url = "https://myWebServer"
$web = New-Object Net.WebClient
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
//[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { customSslCertValidation } #I would like to do something like this
$output = $web.DownloadString($url)
Write-Host $output
Try something like this:
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
$c = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1]
($c.Thumbprint -eq "StoredOrRetrievedHash")
}
This checks the Thumbprint of the certificate returned as part of the request against the string "StoredOrRetrievedHash". You would want to replace that with the details from your certificate loaded in dynamically. It is worth noting that the first line of the scriptblock delegate casts the second element of the $args array to be an object of type X509Certificate2, as the bare X509Certificate object doesn't expose the Thumbprint property.
Note: this only works in PowerShell v2 and later - in v1 assigning an arbitrary scriptblock to a delegate was a lot of extra work and quite frankly, just not worth the effort typically.