Sample code for 30+ languages & platforms
DataFlex Requires Chilkat v11.6.0+

Derive a Key from a Password with Argon2

Demonstrates Crypt2.Argon2DeriveKey, which derives a key from a password using Argon2. The options JSON requires a salt (chosen and stored by the application) and accepts the cost parameters variant, version, iterations, memoryCostKb, parallelism, and keyLen.

Background. Argon2 (RFC 9106) is a memory-hard function that is deliberately expensive in CPU time and memory, which is what makes brute-forcing the password space costly. The argon2id variant is recommended unless there is a specific reason to choose argon2i or argon2d. memoryCostKb does the most to make an attack expensive. The salt, cost parameters, and options must be stored so the same key can be re-derived.

Chilkat DataFlex Downloads

DataFlex
Use ChilkatAx-win32.pkg

Procedure Test
    Boolean iSuccess
    Handle hoCrypt
    String sPassword
    String sSaltB64
    Handle hoJson
    Variant vBdKey
    Handle hoBdKey
    String sKeyHex
    String sTemp1
    Integer iTemp1
    Boolean bTemp1

    Move False To iSuccess

    Get Create (RefClass(cComChilkatCrypt2)) To hoCrypt
    If (Not(IsComObjectCreated(hoCrypt))) Begin
        Send CreateComObject of hoCrypt
    End

    //  The password should come from a secure source rather than being hard-coded.
    Move "correct horse battery staple" To sPassword

    //  A key-derivation salt is chosen and stored by the application.  Generate 16 random bytes and use
    //  them (base64) as the salt.  The salt encoding defaults to base64.
    Set ComEncodingMode Of hoCrypt To "base64"
    Get ComGenRandomBytesENC Of hoCrypt 16 To sSaltB64

    //  Build the Argon2 options JSON.  Only "salt" is required; every other member is optional and shown
    //  here with a typical explicit value:
    //    variant       argon2id (default), argon2i, or argon2d
    //    version       19 (default, 0x13) or 16 (0x10)
    //    iterations    passes over memory (t), >= 1, default 3
    //    memoryCostKb  memory in KB (m), >= 8*parallelism, default 65536 (64 MB)
    //    parallelism   lanes (p), default 1
    //    keyLen        derived key length in bytes, 4..1048576, default 32
    Get Create (RefClass(cComChilkatJsonObject)) To hoJson
    If (Not(IsComObjectCreated(hoJson))) Begin
        Send CreateComObject of hoJson
    End
    Get ComUpdateString Of hoJson "variant" "argon2id" To iSuccess
    Get ComUpdateInt Of hoJson "version" 19 To iSuccess
    Get ComUpdateInt Of hoJson "iterations" 3 To iSuccess
    Get ComUpdateInt Of hoJson "memoryCostKb" 65536 To iSuccess
    Get ComUpdateInt Of hoJson "parallelism" 1 To iSuccess
    Get ComUpdateInt Of hoJson "keyLen" 32 To iSuccess
    Get ComUpdateString Of hoJson "salt" sSaltB64 To iSuccess

    //  Derive the key.  The derived key is returned in the BinData (cleared first).
    Get Create (RefClass(cComChilkatBinData)) To hoBdKey
    If (Not(IsComObjectCreated(hoBdKey))) Begin
        Send CreateComObject of hoBdKey
    End
    Get ComEmit Of hoJson To sTemp1
    Get pvComObject of hoBdKey to vBdKey
    Get ComArgon2DeriveKey Of hoCrypt sPassword sTemp1 vBdKey To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoCrypt To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    //  The application stores the salt and cost parameters so the same key can be re-derived later.
    Get ComGetEncoded Of hoBdKey "hex" To sKeyHex
    Get ComLastMethodSuccess Of hoBdKey To bTemp1
    If (bTemp1 = False) Begin
        Get ComLastErrorText Of hoBdKey To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComNumBytes Of hoBdKey To iTemp1
    Showln "Derived " iTemp1 "-byte key: " sKeyHex


End_Procedure