Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

Post your working scripts, libraries and tools for AHK v1.1 and older
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

11 Apr 2021, 06:45

https://developers.google.com/identity/protocols/oauth2/service-account
1 variant.
Key should be saved as p12.

Code: Select all

certificate := "C:\blah-blah-blah\certain-haiku-23150.p12"
privateKeyPassword := "notasecret"
clientEmail := "[email protected]"

DllCall("LoadLibrary", "str", "bcrypt.dll")
DllCall("LoadLibrary", "str", "ncrypt.dll")
DllCall("LoadLibrary", "str", "crypt32.dll")
time := A_NowUTC
EnvSub, time, 19700101000000, seconds
expTime := time+3600
header = {"alg":"RS256","typ":"JWT"}
payload = {"iss":"%clientEmail%","scope":"https://www.googleapis.com/auth/prediction","aud":"https://oauth2.googleapis.com/token","iat":%time%,"exp":%expTime%}
header := Base64URLenc(header)
payload := Base64URLenc(payload)
file := FileOpen(certificate, "r")
bufLen := file.rawRead(buffer, file.Length)
file.Close()
VarSetCapacity(CRYPT_INTEGER_BLOB, A_PtrSize*2, 0)
NumPut(bufLen, CRYPT_INTEGER_BLOB, 0, "uint")
NumPut(&buffer, CRYPT_INTEGER_BLOB, A_PtrSize, "ptr")
hCertStore := DllCall("crypt32\PFXImportCertStore", "ptr", &CRYPT_INTEGER_BLOB, "str", PrivateKeyPassword, "uint", 0)
hContext := DllCall("crypt32\CertFindCertificateInStore", "ptr", hCertStore, "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "uint", 0, "uint", CERT_FIND_ANY := 0, "ptr", 0, "ptr", 0)
DllCall("crypt32\CryptAcquireCertificatePrivateKey", "ptr", hContext, "uint", CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG := 0x00040000, "ptr", 0, "ptr*", phKey, "uint*", dwKeySpec, "int*", bFreeHandle)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hHashAlg, "ptr", &(BCRYPT_SHA256_ALGORITHM := "SHA256"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hSignAlg, "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptCreateHash", "ptr", hHashAlg, "ptr*", hHash, "ptr", 0, "uint", 0, "ptr", 0, "uint", 0 , "uint", 0)
size := StrPut(header "." payload, "UTF-8")
VarSetCapacity(pbInput, size, 0)
StrPut(header "." payload, &pbInput, "UTF-8")
size--
DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &pbInput, "uint", size, "uint", 0)
DllCall("bcrypt\BCryptGetProperty", "ptr", hHashAlg, "ptr", &(BCRYPT_HASH_LENGTH := "HashDigestLength"), "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0)
VarSetCapacity(pbHash, cbHash, 0)
DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0)
VarSetCapacity(BCRYPT_PKCS1_PADDING_INFO, A_PtrSize, 0)
NumPut(&BCRYPT_SHA256_ALGORITHM, BCRYPT_PKCS1_PADDING_INFO)
DllCall("ncrypt\NCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", 0, "uint", 0, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
VarSetCapacity(pbSignature, cbSignature, 0)
DllCall("ncrypt\NCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", &pbSignature, "uint", cbSignature, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
signature := Base64URLenc(&pbSignature, cbSignature)
DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hSignAlg, "uint", 0)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hHashAlg, "uint", 0)
DllCall("ncrypt\NCryptFreeObject", "ptr", phKey)
DllCall("crypt32\CertFreeCertificateContext", "ptr", hContext)
DllCall("crypt32\CertCloseStore", "ptr", hCertStore, "uint", CERT_CLOSE_STORE_FORCE_FLAG := 1)
jwt := header "." payload "." signature

HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
HTTP.Open("POST", "https://oauth2.googleapis.com/token", true)
HTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
HTTP.Send("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" jwt)
HTTP.WaitForResponse()
msgbox % HTTP.ResponseText
return



Base64URLenc(pData, size := "")
{
   if (size = "")
   {
      VarSetCapacity(bin, StrPut(pData, "UTF-8"))
      size := StrPut(pData, &bin, "UTF-8") - 1
      pData := &bin
   }
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "ptr", 0, "uint*", chars)
   VarSetCapacity(outData, chars << !!A_IsUnicode, 0)
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "str", outData, "uint*", chars)
   outData := StrReplace(outData, "=")
   outData := StrReplace(outData, "+", "-")
   outData := StrReplace(outData, "/", "_")
   return outData
}
2 variant.
The key is taken directly from json::

Code: Select all

private_key := "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w04MZ4hUBGA2uOCWYXwDkCvA0ANd3n/EOU6sBGKMI3V98nCy5Gwxa9ObW2n\n+2VqcwBaNFC7Dok+XQBVMsE=\n-----END PRIVATE KEY-----\n"
clientEmail := "[email protected]"

DllCall("LoadLibrary", "str", "bcrypt.dll")
DllCall("LoadLibrary", "str", "crypt32.dll")
time := A_NowUTC
EnvSub, time, 19700101000000, seconds
expTime := time+3600
header = {"alg":"RS256","typ":"JWT"}
payload = {"iss":"%clientEmail%","scope":"https://www.googleapis.com/auth/prediction","aud":"https://oauth2.googleapis.com/token","iat":%time%,"exp":%expTime%}
header := Base64URLenc(header)
payload := Base64URLenc(payload)
private_key := StrReplace(private_key, "\n")
len := CryptStringToBinary(private_key, outData)
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", PKCS_PRIVATE_KEY_INFO := 44, "ptr", &outData, "uint", len, "uint", (CRYPT_DECODE_ALLOC_FLAG := 0x8000)|(CRYPT_DECODE_NOCOPY_FLAG := 0x1), "ptr", 0, "ptr*", PrivateKeyInfo, "uint*", cb)
PrivateKeyInfo_PrivateKey_cbData := numget(PrivateKeyInfo+0, 4*A_PtrSize, "uint")
PrivateKeyInfo_PrivateKey_pbData := numget(PrivateKeyInfo+0, 5*A_PtrSize, "ptr")
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", CNG_RSA_PRIVATE_KEY_BLOB := 83, "ptr", PrivateKeyInfo_PrivateKey_pbData, "uint", PrivateKeyInfo_PrivateKey_cbData, "uint", CRYPT_DECODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", prkb, "uint*", cb)
DllCall("LocalFree", "ptr", PrivateKeyInfo)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hSignAlg, "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptImportKeyPair", "ptr", hSignAlg, "ptr", 0, "ptr", &(BCRYPT_RSAPRIVATE_BLOB := "RSAPRIVATEBLOB"), "ptr*", phKey, "ptr", prkb, "uint", cb, "uint", 0)
DllCall("LocalFree", "ptr", prkb)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hHashAlg, "ptr", &(BCRYPT_SHA256_ALGORITHM := "SHA256"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptCreateHash", "ptr", hHashAlg, "ptr*", hHash, "ptr", 0, "uint", 0, "ptr", 0, "uint", 0 , "uint", 0)
size := StrPut(header "." payload, "UTF-8")
VarSetCapacity(pbInput, size, 0)
StrPut(header "." payload, &pbInput, "UTF-8")
size--
DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &pbInput, "uint", size, "uint", 0)
DllCall("bcrypt\BCryptGetProperty", "ptr", hHashAlg, "ptr", &(BCRYPT_HASH_LENGTH := "HashDigestLength"), "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0)
VarSetCapacity(pbHash, cbHash, 0)
DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0)
VarSetCapacity(BCRYPT_PKCS1_PADDING_INFO, A_PtrSize, 0)
NumPut(&BCRYPT_SHA256_ALGORITHM, BCRYPT_PKCS1_PADDING_INFO)
DllCall("bcrypt\BCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", 0, "uint", 0, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
VarSetCapacity(pbSignature, cbSignature, 0)
DllCall("bcrypt\BCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", &pbSignature, "uint", cbSignature, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
signature := Base64URLenc(&pbSignature, cbSignature)
DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hSignAlg, "uint", 0)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hHashAlg, "uint", 0)
DllCall("bcrypt\BCryptDestroyKey", "ptr", phKey)
jwt := header "." payload "." signature

HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
HTTP.Open("POST", "https://oauth2.googleapis.com/token", true)
HTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
HTTP.Send("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" jwt)
HTTP.WaitForResponse()
msgbox % HTTP.ResponseText
return



Base64URLenc(pData, size := "")
{
   if (size = "")
   {
      VarSetCapacity(bin, StrPut(pData, "UTF-8"))
      size := StrPut(pData, &bin, "UTF-8") - 1
      pData := &bin
   }
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "ptr", 0, "uint*", chars)
   VarSetCapacity(outData, chars << !!A_IsUnicode, 0)
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "str", outData, "uint*", chars)
   outData := StrReplace(outData, "=")
   outData := StrReplace(outData, "+", "-")
   outData := StrReplace(outData, "/", "_")
   return outData
}

CryptStringToBinary(string, ByRef outData)
{
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "ptr", 0, "uint*", bytes, "uint*", 0, "uint*", 0)
   VarSetCapacity(outData, bytes) 
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "str", outData, "uint*", bytes, "uint*", 0, "uint*", 0)
   Return bytes
}
Last edited by malcev on 03 Feb 2023, 12:34, edited 1 time in total.
nadure
Posts: 22
Joined: 26 Mar 2021, 23:02
Location: Korea
Contact:

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

12 Apr 2021, 06:36

thx ! :o
I don't know if I'm offended, but I've cleaned it up the codes your example by class.

after viewing your code, i have no idea about getting out public key from private key and using the key and encyrpting it. :crazy:

this is the code for other people who is searching for jwt rs256.

Code: Select all

#Include %A_ScriptDir%\Resource\JsonParser.ahk

token := New JWT_RSA_256("service.json",["https www.googleapis.com /auth/prediction"])  Broken Link for safety

Msgbox,% token.access_token

return

class JWT_RSA_256
{
    __New(file_path, scopes)
    {
        this.check_input_type(file_path, scopes) ; check_input
        this.get_exp_time(now, exp_time) ; set exp_time
        scopes := this.get_scopes(scopes) ; set scopes
        this.get_info_from_file(file_path, private_key, client_email) ; get key, email

        DllCall("LoadLibrary", "str", "bcrypt.dll")
        DllCall("LoadLibrary", "str", "crypt32.dll")

        header := {"alg":"RS256","typ":"JWT"}
        payload := {"iss":client_email
            ,"scope":scopes
            ,"aud":"https oauth2.googleapis.com /token"  Broken Link for safety
            ,"iat":now
            ,"exp":exp_time}
        
        this.header := Base64URLenc(Json.Dump(header))
        this.payload := Base64URLenc(Json.Dump(payload))

        signature := this.encrypt_rsa(private_key)

        jwt := this.header "." this.payload "." signature

        access_token_json := this.get_access_token(jwt)
        ; Msgbox,% access_token_json

        res := Json.Load(access_token_json)
        /*
            res_structure :
                res.access_token -> token_info
                res.expires_in -> expire_info
        */
        return res
    }

    check_input_type(file_path, scopes)
    {
        if(file_path = "")
        {
            throw Exception("There is no filePath.")
        }

        if !FileExist(file_path)
            throw Exception("There is no service token file.")
        
        SplitPath,% file_path, fileName, OutDir, Ext
        if (Ext != "json")
            throw Exception("Service Key's extension is maybe json."
            + " please check the valid filePath.")

        if(scopes.MaxIndex()=0)
        {
            if (scopes="")
                throw Exception("There is no scopes.")
        }

        if(StrLen(scopes) > 0)
            throw Exception("Scopes have to be array. Not string.")
        
        if(not scopes[1])
            throw Exception("Scope value is invalid. Please check that.")

    }

    get_scopes(scopes)
    {
        res := ""
        for k, v in scopes
        {
            res .= v . " "
        }
        return RTrim(res)
    }

    get_info_from_file(file_path, ByRef private_key, ByRef client_email)
    {
        FileRead, file_content, %file_path%
        res := JSON.Load(file_content)
        client_email := res.client_email
        private_key := res.private_key

        if client_email = ""
            throw Exception("There is no client_email value")
        
        if private_key = ""
            throw Exception("There is no private_key value")
    }

    get_exp_time(ByRef time, Byref exp_time)
    {
        time := A_NowUTC
        EnvSub, time, 19700101000000, seconds
        exp_time := time+3600
        this.time := time
    }

    encrypt_rsa(private_key)
    {
        private_key := StrReplace(private_key, "\n")
        len := CryptStringToBinary(private_key, outData)

        header := this.header
        payload := this.payload

        DllCall("crypt32\CryptDecodeObjectEx"
            , "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536)
            , "int", PKCS_PRIVATE_KEY_INFO := 44
            , "ptr", &outData
            , "uint", len
            , "uint", (CRYPT_DECODE_ALLOC_FLAG := 0x8000)|(CRYPT_DECODE_NOCOPY_FLAG := 0x1)
            , "ptr", 0
            , "ptr*", PrivateKeyInfo
            , "uint*", cb)

        PrivateKeyInfo_PrivateKey_cbData := numget(PrivateKeyInfo+0, 4*A_PtrSize, "uint")
        PrivateKeyInfo_PrivateKey_pbData := numget(PrivateKeyInfo+0, 5*A_PtrSize, "uint")

        DllCall("crypt32\CryptDecodeObjectEx"
            , "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536)
            , "int", CNG_RSA_PRIVATE_KEY_BLOB := 83
            , "ptr", PrivateKeyInfo_PrivateKey_pbData
            , "uint", PrivateKeyInfo_PrivateKey_cbData
            , "uint", CRYPT_DECODE_ALLOC_FLAG := 0x8000
            , "ptr", 0
            , "ptr*", prkb
            , "uint*", cb)

        DllCall("LocalFree", "ptr", PrivateKeyInfo)

        DllCall("bcrypt\BCryptOpenAlgorithmProvider"
            , "ptr*", hSignAlg
            , "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA")
            , "ptr", 0
            , "uint", 0)

        DllCall("bcrypt\BCryptImportKeyPair"
            , "ptr", hSignAlg
            , "ptr", 0
            , "ptr", &(BCRYPT_RSAPRIVATE_BLOB := "RSAPRIVATEBLOB")
            , "ptr*", phKey
            , "ptr", prkb
            , "uint", cb
            , "uint", 0)

        DllCall("LocalFree", "ptr", prkb)

        DllCall("bcrypt\BCryptOpenAlgorithmProvider"
            , "ptr*", hHashAlg
            , "ptr", &(BCRYPT_SHA256_ALGORITHM := "SHA256")
            , "ptr", 0
            , "uint", 0)
            
        DllCall("bcrypt\BCryptCreateHash"
            , "ptr", hHashAlg
            , "ptr*", hHash
            , "ptr", 0
            , "uint", 0
            , "ptr", 0
            , "uint", 0 
            , "uint", 0)

        size := StrPut(header "." payload, "UTF-8")
        VarSetCapacity(pbInput, size, 0)
        StrPut(header "." payload, &pbInput, "UTF-8")

        size--
        DllCall("bcrypt\BCryptHashData"
            , "ptr", hHash
            , "ptr", &pbInput
            , "uint", size
            , "uint", 0)

        DllCall("bcrypt\BCryptGetProperty"
            , "ptr", hHashAlg
            , "ptr", &(BCRYPT_HASH_LENGTH := "HashDigestLength")
            , "uint*", cbHash
            , "uint", 4
            , "uint*", cbResult
            , "uint", 0)

        VarSetCapacity(pbHash, cbHash, 0)
        DllCall("bcrypt\BCryptFinishHash"
            , "ptr", hHash
            , "ptr", &pbHash
            , "uint", cbHash
            , "uint", 0)

        VarSetCapacity(BCRYPT_PKCS1_PADDING_INFO, A_PtrSize, 0)
        NumPut(&BCRYPT_SHA256_ALGORITHM, BCRYPT_PKCS1_PADDING_INFO)

        DllCall("bcrypt\BCryptSignHash"
            , "ptr", phKey
            , "ptr", &BCRYPT_PKCS1_PADDING_INFO
            , "ptr", &pbHash
            , "uint", cbHash
            , "ptr", 0
            , "uint", 0
            , "uint*", cbSignature
            , "uint", BCRYPT_PAD_PKCS1 := 2)

        VarSetCapacity(pbSignature, cbSignature, 0)
        DllCall("bcrypt\BCryptSignHash"
            , "ptr", phKey
            , "ptr", &BCRYPT_PKCS1_PADDING_INFO
            , "ptr", &pbHash
            , "uint", cbHash
            , "ptr", &pbSignature
            , "uint", cbSignature
            , "uint*", cbSignature
            , "uint", BCRYPT_PAD_PKCS1 := 2)
        
        signature := Base64URLenc(&pbSignature, cbSignature)

        ; clean up
        DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
        DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hSignAlg, "uint", 0)
        DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hHashAlg, "uint", 0)
        DllCall("bcrypt\BCryptDestroyKey", "ptr", phKey)
        return signature

    }

    get_access_token(jwt)
    {
        HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
        HTTP.Open("POST", "https oauth2.googleapis.com /token"  Broken Link for safety, true)
        HTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
        HTTP.Send("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" jwt)
        HTTP.WaitForResponse()
        return HTTP.ResponseText
    }

}


; Origin codes.
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=89236&p=393379#p393379
; 2021-04-11
; author : malcev 
/*
; key
private_key := "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w04MZ4hUBGA2uOCWYXwDkCvA0ANd3n/EOU6sBGKMI3V98nCy5Gwxa9ObW2n\n+2VqcwBaNFC7Dok+XQBVMsE=\n-----END PRIVATE KEY-----\n"
clientEmail := "[email protected]"

; load dll
DllCall("LoadLibrary", "str", "bcrypt.dll")
DllCall("LoadLibrary", "str", "crypt32.dll")

; set utc
time := A_NowUTC
EnvSub, time, 19700101000000, seconds
expTime := time+3600

; set jwt info
header = {"alg":"RS256","typ":"JWT"}
payload = {"iss":"%clientEmail%","scope":"https www.googleapis.com /auth/prediction","aud":"https  Broken Link for safety oauth2.googleapis.com /token"  Broken Link for safety,"iat":%time%,"exp":%expTime%}

header := Base64URLenc(header)
payload := Base64URLenc(payload)

private_key := StrReplace(private_key, "\n")
len := CryptStringToBinary(private_key, outData)

; do rsa
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", PKCS_PRIVATE_KEY_INFO := 44, "ptr", &outData, "uint", len, "uint", (CRYPT_DECODE_ALLOC_FLAG := 0x8000)|(CRYPT_DECODE_NOCOPY_FLAG := 0x1), "ptr", 0, "ptr*", PrivateKeyInfo, "uint*", cb)
PrivateKeyInfo_PrivateKey_cbData := numget(PrivateKeyInfo+0, 4*A_PtrSize, "uint")
PrivateKeyInfo_PrivateKey_pbData := numget(PrivateKeyInfo+0, 5*A_PtrSize, "uint")
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", CNG_RSA_PRIVATE_KEY_BLOB := 83, "ptr", PrivateKeyInfo_PrivateKey_pbData, "uint", PrivateKeyInfo_PrivateKey_cbData, "uint", CRYPT_DECODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", prkb, "uint*", cb)
DllCall("LocalFree", "ptr", PrivateKeyInfo)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hSignAlg, "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptImportKeyPair", "ptr", hSignAlg, "ptr", 0, "ptr", &(BCRYPT_RSAPRIVATE_BLOB := "RSAPRIVATEBLOB"), "ptr*", phKey, "ptr", prkb, "uint", cb, "uint", 0)
DllCall("LocalFree", "ptr", prkb)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hHashAlg, "ptr", &(BCRYPT_SHA256_ALGORITHM := "SHA256"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptCreateHash", "ptr", hHashAlg, "ptr*", hHash, "ptr", 0, "uint", 0, "ptr", 0, "uint", 0 , "uint", 0)
size := StrPut(header "." payload, "UTF-8")
VarSetCapacity(pbInput, size, 0)
StrPut(header "." payload, &pbInput, "UTF-8")

; skip last EOF(maybe)
size--

; 
DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &pbInput, "uint", size, "uint", 0)
DllCall("bcrypt\BCryptGetProperty", "ptr", hHashAlg, "ptr", &(BCRYPT_HASH_LENGTH := "HashDigestLength"), "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0)
VarSetCapacity(pbHash, cbHash, 0)
DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0)
VarSetCapacity(BCRYPT_PKCS1_PADDING_INFO, A_PtrSize, 0)
NumPut(&BCRYPT_SHA256_ALGORITHM, BCRYPT_PKCS1_PADDING_INFO)
DllCall("bcrypt\BCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", 0, "uint", 0, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
VarSetCapacity(pbSignature, cbSignature, 0)
DllCall("bcrypt\BCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", &pbSignature, "uint", cbSignature, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
signature := Base64URLenc(&pbSignature, cbSignature)

; clean up
DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hSignAlg, "uint", 0)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hHashAlg, "uint", 0)
DllCall("bcrypt\BCryptDestroyKey", "ptr", phKey)


jwt := header "." payload "." signature

; send
HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
HTTP.Open("POST", "https oauth2.googleapis.com /token"  Broken Link for safety, true)
HTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
HTTP.Send("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" jwt)
HTTP.WaitForResponse()
msgbox % HTTP.ResponseText
return

*/

Base64URLenc(pData, size := "")
{
   if (size = "")
   {
      VarSetCapacity(bin, StrPut(pData, "UTF-8"))
      size := StrPut(pData, &bin, "UTF-8") - 1
      pData := &bin
   }
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "ptr", 0, "uint*", chars)
   VarSetCapacity(outData, chars << !!A_IsUnicode, 0)
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "str", outData, "uint*", chars)
   outData := StrReplace(outData, "=")
   outData := StrReplace(outData, "+", "-")
   outData := StrReplace(outData, "/", "_")
   return outData
}

CryptStringToBinary(string, ByRef outData)
{
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "ptr", 0, "uint*", bytes, "uint*", 0, "uint*", 0)
   VarSetCapacity(outData, bytes) 
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "str", outData, "uint*", bytes, "uint*", 0, "uint*", 0)
   Return bytes
}
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

12 Apr 2021, 09:23

i have no idea about getting out public key from private key
May be You can do it with BCryptExportKey function with BCRYPT_RSAPUBLIC_BLOB as blob type.
nadure
Posts: 22
Joined: 26 Mar 2021, 23:02
Location: Korea
Contact:

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

12 Apr 2021, 23:10

malcev wrote:
12 Apr 2021, 09:23
i have no idea about getting out public key from private key
May be You can do it with BCryptExportKey function with BCRYPT_RSAPUBLIC_BLOB as blob type.
thanks for the information!

i'll try it
User avatar
Nofosto
Posts: 3
Joined: 16 Sep 2021, 14:28

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

16 Sep 2021, 14:41

Hello People!

First of all. Thanks for the amazing scripts it helped tons! I'm wonder if someone has a base script for google OAuth 2.0 private user data. I'm trying to interact with google sheets spreadsheet, but I don't know how to authenticate the user and refresh the token once it has expired. Right now I'm using Postman to get the Access Token and use on my AHK script with WinHttp.

Any help or directions would be really appreciated!
User avatar
Nofosto
Posts: 3
Joined: 16 Sep 2021, 14:28

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

21 Sep 2021, 08:48

malcev wrote:
20 Sep 2021, 02:42
viewtopic.php?p=263499#p263499
Amazing. Exactly what I needed. I just need to change de scope and other variables to match my Google sheets use case. Thanks!
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

28 Jul 2022, 07:04

malcev wrote:
12 Apr 2021, 09:23
i have no idea about getting out public key from private key
May be You can do it with BCryptExportKey function with BCRYPT_RSAPUBLIC_BLOB as blob type.
nadure wrote:
12 Apr 2021, 23:10
thanks for the information!

i'll try it
did either of you figure out how to import/export both public and private keys to plaintext?

colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

01 Feb 2023, 17:29

Hello, thanks for this. I ran your json example script but the signature is empty. Any ideas of why? I tried on both 32 & 64 bit ahk

jwt := header "." payload "." signature
msgbox % jwt


returns

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzZXJ2aWNlQGNlcnRhaW4taGFpay5nc2VydmljZWFjY291bnQuY29tIiwic2NvcGUiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3ByZWRpY3Rpb24iLCJhdWQiOiJodHRwczovL29hdXRoMi5nb29nbGVhcGlzLmNvbS90b2tlbiIsImlhdCI6MTY3NTI4OTk2MiwiZXhwIjoxNjc1MjkzNTYyfQ.
colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

02 Feb 2023, 11:34

I ended up using web app authorization for my project, but would like to use this method if I could.
I used your exact code & also tried to remove the padding around the key like as below. No signature, no errors, errorLevel is 0 after every dllcall, and on latest version of ahk. Should your example code have signature with the key you gave? Forgive me if I am missing something stupid.

Code: Select all

private_key := "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w04MZ4hUBGA2uOCWYXwDkCvA0ANd3n/EOU6sBGKMI3V98nCy5Gwxa9ObW2n\n+2VqcwBaNFC7Dok+XQBVMsE=\n-----END PRIVATE KEY-----\n"
private_key := StrReplace(private_key, "\n")
private_key := StrReplace(private_key, "-----BEGIN PRIVATE KEY-----")
private_key := StrReplace(private_key, "-----END PRIVATE KEY-----")
msgbox % clipboard := private_key
clientEmail := "[email protected]"

DllCall("LoadLibrary", "str", "bcrypt.dll")
DllCall("LoadLibrary", "str", "crypt32.dll")
time := A_NowUTC
EnvSub, time, 19700101000000, seconds
expTime := time+3600
header = {"alg":"RS256","typ":"JWT"}
payload = {"iss":"%clientEmail%","scope":"https://www.googleapis.com/auth/prediction","aud":"https://oauth2.googleapis.com/token","iat":%time%,"exp":%expTime%}
header := Base64URLenc(header)
payload := Base64URLenc(payload)

len := CryptStringToBinary(private_key, outData)
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", PKCS_PRIVATE_KEY_INFO := 44, "ptr", &outData, "uint", len, "uint", (CRYPT_DECODE_ALLOC_FLAG := 0x8000)|(CRYPT_DECODE_NOCOPY_FLAG := 0x1), "ptr", 0, "ptr*", PrivateKeyInfo, "uint*", cb)
PrivateKeyInfo_PrivateKey_cbData := numget(PrivateKeyInfo+0, 4*A_PtrSize, "uint")
PrivateKeyInfo_PrivateKey_pbData := numget(PrivateKeyInfo+0, 5*A_PtrSize, "uint")
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", CNG_RSA_PRIVATE_KEY_BLOB := 83, "ptr", PrivateKeyInfo_PrivateKey_pbData, "uint", PrivateKeyInfo_PrivateKey_cbData, "uint", CRYPT_DECODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", prkb, "uint*", cb)
DllCall("LocalFree", "ptr", PrivateKeyInfo)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hSignAlg, "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptImportKeyPair", "ptr", hSignAlg, "ptr", 0, "ptr", &(BCRYPT_RSAPRIVATE_BLOB := "RSAPRIVATEBLOB"), "ptr*", phKey, "ptr", prkb, "uint", cb, "uint", 0)
DllCall("LocalFree", "ptr", prkb)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hHashAlg, "ptr", &(BCRYPT_SHA256_ALGORITHM := "SHA256"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptCreateHash", "ptr", hHashAlg, "ptr*", hHash, "ptr", 0, "uint", 0, "ptr", 0, "uint", 0 , "uint", 0)
size := StrPut(header "." payload, "UTF-8")
VarSetCapacity(pbInput, size, 0)
StrPut(header "." payload, &pbInput, "UTF-8")
size--
DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &pbInput, "uint", size, "uint", 0)
DllCall("bcrypt\BCryptGetProperty", "ptr", hHashAlg, "ptr", &(BCRYPT_HASH_LENGTH := "HashDigestLength"), "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0)
VarSetCapacity(pbHash, cbHash, 0)
DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0)
VarSetCapacity(BCRYPT_PKCS1_PADDING_INFO, A_PtrSize, 0)
NumPut(&BCRYPT_SHA256_ALGORITHM, BCRYPT_PKCS1_PADDING_INFO)
DllCall("bcrypt\BCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", 0, "uint", 0, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
VarSetCapacity(pbSignature, cbSignature, 0)
DllCall("bcrypt\BCryptSignHash", "ptr", phKey, "ptr", &BCRYPT_PKCS1_PADDING_INFO, "ptr", &pbHash, "uint", cbHash, "ptr", &pbSignature, "uint", cbSignature, "uint*", cbSignature, "uint", BCRYPT_PAD_PKCS1 := 2)
signature := Base64URLenc(&pbSignature, cbSignature)
DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hSignAlg, "uint", 0)
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hHashAlg, "uint", 0)
DllCall("bcrypt\BCryptDestroyKey", "ptr", phKey)
jwt := header "." payload "." signature
msgbox % clipboard := jwt 
return

Base64URLenc(pData, size := "")
{
   if (size = "")
   {
      VarSetCapacity(bin, StrPut(pData, "UTF-8"))
      size := StrPut(pData, &bin, "UTF-8") - 1
      pData := &bin
   }
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "ptr", 0, "uint*", chars)
   VarSetCapacity(outData, chars << !!A_IsUnicode, 0)
   DllCall("crypt32\CryptBinaryToString", "ptr", pData, "uint", size, "uint", (CRYPT_STRING_BASE64 := 0x1)|(CRYPT_STRING_NOCRLF := 0x40000000), "str", outData, "uint*", chars)
   outData := StrReplace(outData, "=")
   outData := StrReplace(outData, "+", "-")
   outData := StrReplace(outData, "/", "_")
   return outData
}

CryptStringToBinary(string, ByRef outData)
{
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "ptr", 0, "uint*", bytes, "uint*", 0, "uint*", 0)
   VarSetCapacity(outData, bytes) 
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "str", outData, "uint*", bytes, "uint*", 0, "uint*", 0)
   Return bytes
}
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

02 Feb 2023, 11:39

You just need to set Your private key and email.
My private key - does not work (just for example).
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

04 Feb 2023, 21:42

guest3456 wrote:
28 Jul 2022, 07:04
did either of you figure out how to import/export both public and private keys to plaintext?
I think it can be done like this:

Code: Select all

DllCall("LoadLibrary", "str", "bcrypt.dll")
DllCall("LoadLibrary", "str", "crypt32.dll")

; generate keys
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hSignAlg, "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptGenerateKeyPair", "ptr", hSignAlg, "ptr*", phKey, "uint", 512, "uint", 0)
DllCall("bcrypt\BCryptFinalizeKeyPair", "ptr", phKey, "uint", 0)

; extract private key
DllCall("bcrypt\BCryptExportKey", "ptr", phKey, "ptr", 0, "ptr", &(BCRYPT_RSAFULLPRIVATE_BLOB := "RSAFULLPRIVATEBLOB"), "ptr", 0, "uint", 0, "uint*", cbKey, "uint", 0)
VarSetCapacity(pbKey, cbKey, 0)
DllCall("bcrypt\BCryptExportKey", "ptr", phKey, "ptr", 0, "ptr", &(BCRYPT_RSAFULLPRIVATE_BLOB := "RSAFULLPRIVATEBLOB"), "ptr", &pbKey, "uint", cbKey, "uint*", cbKey, "uint", 0)
DllCall("crypt32\CryptEncodeObjectEx", "uint", X509_ASN_ENCODING := 1, "int", CNG_RSA_PRIVATE_KEY_BLOB := 83, "ptr", &pbKey, "uint", CRYPT_ENCODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", KeyInfo, "uint*", cbData)
varsetcapacity(szOID_RSA_RSA, 22, 0)
StrPut("1.2.840.113549.1.1.1", &szOID_RSA_RSA, "utf-8")
varsetcapacity(CRYPT_PRIVATE_KEY_INFO, A_PtrSize*7, 0)
NumPut(&szOID_RSA_RSA, CRYPT_PRIVATE_KEY_INFO, A_PtrSize, "ptr")
NumPut(cbData, CRYPT_PRIVATE_KEY_INFO, 4*A_PtrSize, "uint")
NumPut(KeyInfo, CRYPT_PRIVATE_KEY_INFO, 5*A_PtrSize, "ptr")
DllCall("crypt32\CryptEncodeObjectEx", "uint", X509_ASN_ENCODING := 1, "int", PKCS_PRIVATE_KEY_INFO := 44, "ptr", &CRYPT_PRIVATE_KEY_INFO, "uint", CRYPT_ENCODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", pbKey, "uint*", cbkey)
DllCall("crypt32\CryptBinaryToString", "ptr", pbKey, "uint", cbkey, "uint", CRYPT_STRING_BASE64 := 0x1, "ptr", 0, "uint*", chars)
VarSetCapacity(outData, chars*2, 0)
DllCall("crypt32\CryptBinaryToString", "ptr", pbKey, "uint", cbkey, "uint", CRYPT_STRING_BASE64 := 0x1, "str", outData, "uint*", chars)
DllCall("LocalFree", "ptr", KeyInfo)
DllCall("LocalFree", "ptr", pbKey)
msgbox % outData

; extract public key
DllCall("bcrypt\BCryptExportKey", "ptr", phKey, "ptr", 0, "ptr", &(BCRYPT_RSAPUBLIC_BLOB := "RSAPUBLICBLOB"), "ptr", 0, "uint", 0, "uint*", cbKey, "uint", 0)
VarSetCapacity(pbKey, cbKey, 0)
DllCall("bcrypt\BCryptExportKey", "ptr", phKey, "ptr", 0, "ptr", &(BCRYPT_RSAPUBLIC_BLOB := "RSAPUBLICBLOB"), "ptr", &pbKey, "uint", cbKey, "uint*", cbKey, "uint", 0)
DllCall("crypt32\CryptEncodeObjectEx", "uint", X509_ASN_ENCODING := 1, "int", CNG_RSA_PUBLIC_KEY_BLOB := 72, "ptr", &pbKey, "uint", CRYPT_ENCODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", KeyInfo, "uint*", cbData)
varsetcapacity(szOID_RSA_RSA, 22, 0)
StrPut("1.2.840.113549.1.1.1", &szOID_RSA_RSA, "utf-8")
varsetcapacity(CERT_PUBLIC_KEY_INFO, A_PtrSize*6, 0)
NumPut(&szOID_RSA_RSA, CERT_PUBLIC_KEY_INFO, 0, "ptr")
NumPut(cbData, CERT_PUBLIC_KEY_INFO, 3*A_PtrSize, "uint")
NumPut(KeyInfo, CERT_PUBLIC_KEY_INFO, 4*A_PtrSize, "ptr")
DllCall("crypt32\CryptEncodeObjectEx", "uint", X509_ASN_ENCODING := 1, "int", X509_PUBLIC_KEY_INFO := 8, "ptr", &CERT_PUBLIC_KEY_INFO, "uint", CRYPT_ENCODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", pbKey, "uint*", cbkey)
DllCall("crypt32\CryptBinaryToString", "ptr", pbKey, "uint", cbkey, "uint", CRYPT_STRING_BASE64 := 0x1, "ptr", 0, "uint*", chars)
VarSetCapacity(outData, chars*2, 0)
DllCall("crypt32\CryptBinaryToString", "ptr", pbKey, "uint", cbkey, "uint", CRYPT_STRING_BASE64 := 0x1, "str", outData, "uint*", chars)
DllCall("LocalFree", "ptr", KeyInfo)
DllCall("LocalFree", "ptr", pbKey)
msgbox % outData

; destroy keys
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hSignAlg, "uint", 0)
DllCall("bcrypt\BCryptDestroyKey", "ptr", phKey)
BTW found good online tools for working with encription/decryption/encoding/decoding/validation
http://tool.chacuo.net/cryptrsakeyvalid
Last edited by malcev on 06 Feb 2023, 05:25, edited 1 time in total.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

05 Feb 2023, 22:17

malcev wrote:
04 Feb 2023, 21:42
I think it can be done like this:

Code: Select all

StrPut("1.2.840.113549.1.1.1", &szOID_RSA_RSA, "utf-8")
excellent. what is that magic number above?

also, is there a way to import those plaintext keys back inside the crypto api? so like, the user can export those plaintext keys to disk, and then reimport them later to sign? or import them into openssl?

malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

06 Feb 2023, 05:24

szOID_RSA_RSA = "1.2.840.113549.1.1.1" it is oid of algorithm
https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-crypt_algorithm_identifier
Yes, We can import those plaintext keys back inside the crypto api.
When We export private key We get this key in the same format, like We receive it from google json.
So We can import it like in the second example in the first post

Code: Select all

DllCall("LoadLibrary", "str", "bcrypt.dll")
DllCall("LoadLibrary", "str", "crypt32.dll")

; generate keys
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hSignAlg, "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptGenerateKeyPair", "ptr", hSignAlg, "ptr*", phKey, "uint", 512, "uint", 0)
DllCall("bcrypt\BCryptFinalizeKeyPair", "ptr", phKey, "uint", 0)

; extract private key
DllCall("bcrypt\BCryptExportKey", "ptr", phKey, "ptr", 0, "ptr", &(BCRYPT_RSAFULLPRIVATE_BLOB := "RSAFULLPRIVATEBLOB"), "ptr", 0, "uint", 0, "uint*", cbKey, "uint", 0)
VarSetCapacity(pbKey, cbKey, 0)
DllCall("bcrypt\BCryptExportKey", "ptr", phKey, "ptr", 0, "ptr", &(BCRYPT_RSAFULLPRIVATE_BLOB := "RSAFULLPRIVATEBLOB"), "ptr", &pbKey, "uint", cbKey, "uint*", cbKey, "uint", 0)
DllCall("crypt32\CryptEncodeObjectEx", "uint", X509_ASN_ENCODING := 1, "int", CNG_RSA_PRIVATE_KEY_BLOB := 83, "ptr", &pbKey, "uint", CRYPT_ENCODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", KeyInfo, "uint*", cbData)
varsetcapacity(szOID_RSA_RSA, 22, 0)
StrPut("1.2.840.113549.1.1.1", &szOID_RSA_RSA, "utf-8")
varsetcapacity(CRYPT_PRIVATE_KEY_INFO, A_PtrSize*7, 0)
NumPut(&szOID_RSA_RSA, CRYPT_PRIVATE_KEY_INFO, A_PtrSize, "ptr")
NumPut(cbData, CRYPT_PRIVATE_KEY_INFO, 4*A_PtrSize, "uint")
NumPut(KeyInfo, CRYPT_PRIVATE_KEY_INFO, 5*A_PtrSize, "ptr")
DllCall("crypt32\CryptEncodeObjectEx", "uint", X509_ASN_ENCODING := 1, "int", PKCS_PRIVATE_KEY_INFO := 44, "ptr", &CRYPT_PRIVATE_KEY_INFO, "uint", CRYPT_ENCODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", pbKey, "uint*", cbkey)
DllCall("crypt32\CryptBinaryToString", "ptr", pbKey, "uint", cbkey, "uint", CRYPT_STRING_BASE64 := 0x1, "ptr", 0, "uint*", chars)
VarSetCapacity(outData, chars*2, 0)
DllCall("crypt32\CryptBinaryToString", "ptr", pbKey, "uint", cbkey, "uint", CRYPT_STRING_BASE64 := 0x1, "str", outData, "uint*", chars)
DllCall("LocalFree", "ptr", KeyInfo)
DllCall("LocalFree", "ptr", pbKey)
msgbox % private_key := "-----BEGIN PRIVATE KEY-----\n" strreplace(outData, "`r`n", "\n") "-----END PRIVATE KEY-----\n"

; destroy keys
DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hSignAlg, "uint", 0)
DllCall("bcrypt\BCryptDestroyKey", "ptr", phKey)

; import private key
private_key := StrReplace(private_key, "\n")
len := CryptStringToBinary(private_key, outData)
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", PKCS_PRIVATE_KEY_INFO := 44, "ptr", &outData, "uint", len, "uint", (CRYPT_DECODE_ALLOC_FLAG := 0x8000)|(CRYPT_DECODE_NOCOPY_FLAG := 0x1), "ptr", 0, "ptr*", PrivateKeyInfo, "uint*", cb)
PrivateKeyInfo_PrivateKey_cbData := numget(PrivateKeyInfo+0, 4*A_PtrSize, "uint")
PrivateKeyInfo_PrivateKey_pbData := numget(PrivateKeyInfo+0, 5*A_PtrSize, "ptr")
DllCall("crypt32\CryptDecodeObjectEx", "uint", (X509_ASN_ENCODING := 1)|(PKCS_7_ASN_ENCODING := 65536), "int", CNG_RSA_PRIVATE_KEY_BLOB := 83, "ptr", PrivateKeyInfo_PrivateKey_pbData, "uint", PrivateKeyInfo_PrivateKey_cbData, "uint", CRYPT_DECODE_ALLOC_FLAG := 0x8000, "ptr", 0, "ptr*", prkb, "uint*", cb)
DllCall("LocalFree", "ptr", PrivateKeyInfo)
DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hSignAlg, "ptr", &(BCRYPT_RSA_ALGORITHM := "RSA"), "ptr", 0, "uint", 0)
DllCall("bcrypt\BCryptImportKeyPair", "ptr", hSignAlg, "ptr", 0, "ptr", &(BCRYPT_RSAPRIVATE_BLOB := "RSAPRIVATEBLOB"), "ptr*", phKey, "ptr", prkb, "uint", cb, "uint", 0)


CryptStringToBinary(string, ByRef outData)
{
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "ptr", 0, "uint*", bytes, "uint*", 0, "uint*", 0)
   VarSetCapacity(outData, bytes) 
   DllCall("Crypt32\CryptStringToBinary", "ptr", &string, "uint", StrLen(string), "uint", CRYPT_STRING_BASE64HEADER := 0, "str", outData, "uint*", bytes, "uint*", 0, "uint*", 0)
   Return bytes
}
User avatar
Xeo786
Posts: 759
Joined: 09 Nov 2015, 02:43
Location: Karachi, Pakistan

Re: Creating signed JWT with RS256 (RSA Signature with SHA-256) for Google Oauth2 authenticating with service account

07 Feb 2023, 04:26

Thank You SO much for this GEM...! :D
"When there is no gravity, there is absolute vacuum and light travel with no time" -Game changer theory

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 107 guests