Forum Discussion

quangtran's avatar
Icon for Cirrus rankCirrus
Dec 21, 2022

use irule to digitally sign

Hello everyone, I have a request like this:


    "Data": "eyJVc2VyTmFtZSI6ImVjdXN0b21zIiwiUGdCJ9"


Here is the body when calling on F5.

Add Sign to call the server as follows:


    "Data": "eyJVc2VyTmFtZSI6ImVjdXN0b21zIiwiUGdCJ9",

    "Signature": {

        "Sign": {

            "Signature_Value": "B35uPWwF9ujq1zXbpsU3xFYPPI78nmqRagGG3p8yqVn+lDqNstTH3BewfA3SN8g=",





- The algorithm is as follows

hash data with SHA256 then encrypt RSA with private key -> return 1 signature string + file cer (public key)


- I consulted from Kai_Wilke and write irule similar to this, but it doesn't work.

when RULE_INIT {
set static::max_payload_size "1048576" ;
set pub_key "NRLtULvKDtRjzevpNPz/BRDfTRKh9i
set pri_key "X7udSSJCpsnZFdv7CFqeqHPrUshldx
if { ( [string tolower [HTTP::path]] equals "/api/xxxx/yyyy" )
and ( [HTTP::method] equals "POST")
and ( [HTTP::header value "Content-Length"] ne "" )
and ( [HTTP::header value "Content-Length"] < $static::max_payload_size ) } then {
HTTP::collect [HTTP::header value "Content-Length"]
set temp(data) [HTTP::payload]
set temp(hash_data) [CRYPTO::hash -alg sha256 $temp(data) ]
set temp(enc_data) [CRYPTO::encrypt -alg RSA -key $pri_key $temp(hash_data) ]
set temp(new_payload) "[string trimright [HTTP::payload] "\}"],\"Signature_Value\":\"$temp(enc_data)\"\,\"Key_info\":\"$pub_key\"\}"
HTTP::payload replace 0 [HTTP::payload length] $temp(new_payload)
unset -nocomplain temp


What do I need to change here?

Any and all help is appreciated. Thanks you


7 Replies

  • Hi quangtran,

    I'm really not sure at this point about what's wrong, but I always find that some logging within iRules can help you in debugging what's happening.

    For instance, you can add a line like this:

    log local0. "encrypted data = $enc_data"

    ...after the CRYPTO::encrypt function, to make sure what has been calculated thus far in your iRule makes sense.

    With local0, the logs will be inserted in /var/log/ltm.

    If your VS is running on plain HTTP, a simple tcpdump will also help understand what's coming in and what's going out.


    • quangtran's avatar
      Icon for Cirrus rankCirrus

      Thanks Mike,   

      Thank you and really appreciate the feedback. 

  • Hi, I haven't tested but maybe is just below line

    set temp(enc_data) [CRYPTO::encrypt -alg rsa-priv -key $pri_key $temp(hash_data) ]

  • Hi Quangtran,

    > What do I need to change here?

    you will need to change those two things...

    1.) Your pub/pri key is stored in the RULE_INIT event in a global varibable. Those can't become accessed from the HTTP_REQUEST* events via $pri_key / $priv_key, you would need to prefix those global varibals to $::pri_key and $::pub_key, but this HIGHLY NOT recommended, since it would disable CMP-mode for the entire Virtual Server. Rename those variables to $static::pub_key and static::pri_key to make them accessible in the HTTP_REQUEST events without loosing CMP-mode is my recommendation.

    2.) You include the raw RSA encrypted data without applying any encodings to the message. This may break the JSON message syntax, if the RSA output contains non-escaped character used by JSON (e.g. " { } , ). Apply [b64encode $temp(enc_data)] before inserting it to the JSON message.

    Cheers, Kai

    • quangtran's avatar
      Icon for Cirrus rankCirrus

      my data was base64 encoded before sending, thanks for your suggestion. 

      can i extract the data with this command: 

      when HTTP_REQUEST_DATA {
      set temp(data) [findstr [HTTP::payload] "\"\Data\"\: 9 \"\ "]

      • Kai_Wilke's avatar
        Icon for MVP rankMVP

        The output of the CRYPTO::encrypt command is binary data and should be encoded before inserted in Json. Otherwise it may crash an ordinary Json parser on every N request... 

        Cheers, Kai