Sample code for 30+ languages & platforms
PureBasic

ECDSA Sign Data and Get Raw R and S Values

See more ECC Examples

Demonstrates getting the raw R and S value of an ECDSA signature.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkPrivateKey.pb"
IncludeFile "CkBinData.pb"
IncludeFile "CkEcc.pb"
IncludeFile "CkAsn.pb"
IncludeFile "CkPrng.pb"
IncludeFile "CkXml.pb"
IncludeFile "CkCrypt2.pb"

Procedure ChilkatExample()

    success.i = 0

    ; This example requires the Chilkat API to have been previously unlocked.
    ; See Global Unlock Sample for sample code.

    ; To create an ECDSA signature, the data first needs to be hashed.  Then the hash
    ; is signed.

    crypt.i = CkCrypt2::ckCreate()
    If crypt.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkCrypt2::setCkHashAlgorithm(crypt, "SHA256")
    CkCrypt2::setCkCharset(crypt, "utf-8")
    CkCrypt2::setCkEncodingMode(crypt, "base64")

    ; Hash a string.
    hash1.s = CkCrypt2::ckHashStringENC(crypt,"The quick brown fox jumps over the lazy dog")
    Debug "hash1 = " + hash1

    ; -----------------------------------------------------------
    ; An ECDSA private key is used for signing.  The public key is for signature verification.
    ; Load our ECC private key.
    ; Our private key file contains this:

    ; 	// -----BEGIN PRIVATE KEY-----
    ; 	MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3J8q/24D1sEKGdP9
    ; 	72MGYElLGpw/a56Y3t6pfON3uhShRANCAATlSmoizyhAwoYZAOuFBATl07/1RR54
    ; 	a1Dzfm16grxJe666AGKR+bSs24hk7TEpaeCTvT8YOOM3l+xKFg7zq6Q9
    ; 	-----END PRIVATE KEY-----

    privKey.i = CkPrivateKey::ckCreate()
    If privKey.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkPrivateKey::ckLoadPemFile(privKey,"qa_data/ecc/secp256r1-key-pkcs8.pem")
    If success <> 1
        Debug CkPrivateKey::ckLastErrorText(privKey)
        CkCrypt2::ckDispose(crypt)
        CkPrivateKey::ckDispose(privKey)
        ProcedureReturn
    EndIf

    ; Sign the hash..
    prng.i = CkPrng::ckCreate()
    If prng.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ecdsa.i = CkEcc::ckCreate()
    If ecdsa.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ecdsaSigBase64.s = CkEcc::ckSignHashENC(ecdsa,hash1,"base64",privKey,prng)
    If CkEcc::ckLastMethodSuccess(ecdsa) <> 1
        Debug CkEcc::ckLastErrorText(ecdsa)
        CkCrypt2::ckDispose(crypt)
        CkPrivateKey::ckDispose(privKey)
        CkPrng::ckDispose(prng)
        CkEcc::ckDispose(ecdsa)
        ProcedureReturn
    EndIf

    ; The ECDSA signature is ASN.1 that contains a sequence of 2 large integers (r and s)
    ; For example:
    ; SEQUENCE (2 elem)
    ;   INTEGER (255 bit) 792134D9B4AD82D5431ED03835A88E2596EB35E5B13054BD9B05A0069281ACC9
    ;   INTEGER (255 bit) 481E758CC1E3CBF825537EC3D9A2CA627E5FAD1137BBEA65DF38658DCB0A9ED5

    Debug "Base64 ECDSA signature = " + ecdsaSigBase64

    ; If the raw R and S values are needed, here's how to get them:
    asn.i = CkAsn::ckCreate()
    If asn.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkAsn::ckLoadEncoded(asn,ecdsaSigBase64,"base64")
    If success = 0
        Debug CkAsn::ckLastErrorText(asn)
        CkCrypt2::ckDispose(crypt)
        CkPrivateKey::ckDispose(privKey)
        CkPrng::ckDispose(prng)
        CkEcc::ckDispose(ecdsa)
        CkAsn::ckDispose(asn)
        ProcedureReturn
    EndIf

    ; The R and X will be in hexidecimal in the XML.
    xml.i = CkXml::ckCreate()
    If xml.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::ckLoadXml(xml,CkAsn::ckAsnToXml(asn))
    Debug CkXml::ckGetXml(xml)

    ; The XML looks like this:
    ; <sequence>
    ; <int>792134D9B4AD82D5431ED03835A88E2596EB35E5B13054BD9B05A0069281ACC9</int>
    ; <int>481E758CC1E3CBF825537EC3D9A2CA627E5FAD1137BBEA65DF38658DCB0A9ED5</int>
    ; </sequence>

    ; Copy raw R and S hex values into a Chilkat BinData object.
    bd.i = CkBinData::ckCreate()
    If bd.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    r.s = CkXml::ckGetChildContent(xml,"int[0]")
    s.s = CkXml::ckGetChildContent(xml,"int[1]")
    CkBinData::ckAppendEncoded(bd,r,"hex")
    CkBinData::ckAppendEncoded(bd,s,"hex")

    Debug "Number of bytes in bd: " + Str(CkBinData::ckNumBytes(bd))


    CkCrypt2::ckDispose(crypt)
    CkPrivateKey::ckDispose(privKey)
    CkPrng::ckDispose(prng)
    CkEcc::ckDispose(ecdsa)
    CkAsn::ckDispose(asn)
    CkXml::ckDispose(xml)
    CkBinData::ckDispose(bd)


    ProcedureReturn
EndProcedure