Forum Discussion

quangtran's avatar
quangtran
Icon for Cirrus rankCirrus
Nov 28, 2022

use irule to sign data using sha256

Hello everyone, I have a request like this:

HTTP REQUEST
- header
POST /login HTTP1/1
Host: xxxxxx
<some other fields>
- Body:
<data>

----> f5 receives and uses Irule to modify the HTTP REQUEST as follows:
- Header: Unchanged
- Body:
<data> + <Hash the data string using SHA256 with the key xxxxx>
---> f5 forward request to pool 

I want to use irule to do this, help me!

Any and all help is appreciated. Thanks

  • Hi Quangtran,

    do you want to calculate the HMAC-checksum for the entire POST-data (Scenario 1) or just the "data" value itself (Scenario 2)?

    Scenario 1:

    hmac-sha256( the received POST string as-is including outer curly braces )

    Scenario 2:

    hmac-sha256( FdQZxoYBLPCgv2VPzdiUDA2Xj9KIJ\/I4BSzViIp\/CG\/ktrcdtXGYXQzGaa71R )

    The quickly code iRule below uses Scenario 1 as input for HMAC calculation. The iRule uses 4 logical steps to read the payload, calculate the checksum, define the new payload and finally insert the new payload to the HTTP request before its getting forwarded to your backend. Every single step could be easily adjusted based on your needs...

     

    when RULE_INIT {
    
    	# Define global configuration options
    
    	set static::max_payload_size "1048576" 		;# Limiter for maximum HTTP payload size in bytes
    	set static::hmac_key "Hello World!"			;# Secrect for HMAC signing
    
    }
    when HTTP_REQUEST {
    
    	# Check if HTTP request contains any HTTP payload and if its size does not exceed our limits...
    
    	if { ( [string tolower [HTTP::path]] equals "/login" )
    	 and ( [HTTP::method] equals "POST" )
    	 and ( [HTTP::header value "Content-Length"] ne "" )
    	 and ( [HTTP::header value "Content-Length"] < $static::max_payload_size ) } then {
    
    		# Collect the HTTP payload and trigger HTTP_REQUEST_DATA event
    		
    		HTTP::collect [HTTP::header value "Content-Length"]
    
    	}
    
    }
    when HTTP_REQUEST_DATA {
    
    	# Define the input used for HMAC signing
    
    	set temp(hmac_input) [HTTP::payload]
    
    	# Compute the HMAC checksum for the input using our secret key
    
    	set temp(hmac_output) [b64encode [CRYPTO::sign -alg hmac-sha256 -key $static::hmac_key $temp(hmac_input)]]
    
    	# Contruct the new payload
    
    	set temp(new_payload) "[string trimright [HTTP::payload] "\}"],\"hashsha256\":\"$temp(hmac_output)\"\}"
    
    	# Replace the payload	
    
    	HTTP::payload replace 0 [HTTP::payload length] $temp(new_payload)
    
    	unset -nocomplain temp
    
    }

     

    At later stage we may or may not combine those 4 logical steps into a single syntax line, to reduce processing overhead to a minimum.. 😉

     

    when HTTP_REQUEST_DATA {
    	
    	# Replace the payload with HMAC signed payload...
    
    	HTTP::payload replace 0 [HTTP::payload length] "[string trimright [HTTP::payload] "\}"],\"hashsha256\":\"[b64encode [CRYPTO::sign -alg hmac-sha256 -key $static::hmac_key [HTTP::payload]]]\"\}"
    	
    }

     

    Cheers, Kai

  • Try this: it will add the hex string to the end of the payload

    when HTTP_REQUEST {
      if { [HTTP::header exists Content-Length] } {
        HTTP::collect [HTTP::header Content-Length]
      }
    }
    when HTTP_REQUEST_DATA {
      set sha [HTTP::payload]
      binary scan $sha h* shahex
      HTTP::payload replace [HTTP::payload length] [string length $shahex] $shahex
    }

     

     

    • quangtran's avatar
      quangtran
      Icon for Cirrus rankCirrus

      Thanks Mohamed,   

      Thank you and really appreciate the feedback. 

  • Hi quangtran,

    I'm not sure If i completely understand your scenario. Lets elaborate your requirements a bit...

    1. You want to extract the POST data posted to /login URI.
    2. You want to calculate a checksum based based on the received POST data, including a shared-key used as checksum authenticator.
    3. You want to append the just calculated checksum to the original POST data an then forward the request to the backend.

    Is this so far correct?

    Question to 2.: How should the checksum be calculated? You want to use a standardized HMAC-SHA256 checksum. Or a homegrown checksum generation (something like sha256( "POST data" + "sharedkey" ).

    Question to 3.: In which format should the checksum be appended to the original POST data. Any special need for sperators between the original POST data and the appended checksum? Any specific encodings (e.g. base64, hex) needed for the binary checksum?

    Cheers, Kai

    • quangtran's avatar
      quangtran
      Icon for Cirrus rankCirrus

      Thank you and really appreciate the feedback. 

      I will answer your question as follows,

      Question 1: all your comments are correct, that's what i want

      Question 2: I want to use a standardized HMAC-SHA256 checksum

      Question 3: I need the checksum to be added to the original POST data in base64 format, and form  

      HTTP REQUEST
      - header: Unchanged
      POST /login HTTP1/1
      Host: xxxxxx
      <some other fields>
      - Body:
      <data> + <Hash the data string using SHA256 > 

      request data

      {"data":"FdQZxoYBLPCgv2VPzdiUDA2Xj9KIJ\/I4BSzViIp\/CG\/ktrcdtXGYXQzGaa71R"

      request data after using iRule

      {"data":"FdQZxoYBLPCgv2VPzdiUDA2Xj9KIJ\/I4BSzViIp\/CG\/ktrcdtXGYXQzGaa71R","hashsha256":"akfjdafjGDJudsjSSlfdjfdsus"} 

       thanks you, Kai

      • Kai_Wilke's avatar
        Kai_Wilke
        Icon for MVP rankMVP

        Hi Quangtran,

        do you want to calculate the HMAC-checksum for the entire POST-data (Scenario 1) or just the "data" value itself (Scenario 2)?

        Scenario 1:

        hmac-sha256( the received POST string as-is including outer curly braces )

        Scenario 2:

        hmac-sha256( FdQZxoYBLPCgv2VPzdiUDA2Xj9KIJ\/I4BSzViIp\/CG\/ktrcdtXGYXQzGaa71R )

        The quickly code iRule below uses Scenario 1 as input for HMAC calculation. The iRule uses 4 logical steps to read the payload, calculate the checksum, define the new payload and finally insert the new payload to the HTTP request before its getting forwarded to your backend. Every single step could be easily adjusted based on your needs...

         

        when RULE_INIT {
        
        	# Define global configuration options
        
        	set static::max_payload_size "1048576" 		;# Limiter for maximum HTTP payload size in bytes
        	set static::hmac_key "Hello World!"			;# Secrect for HMAC signing
        
        }
        when HTTP_REQUEST {
        
        	# Check if HTTP request contains any HTTP payload and if its size does not exceed our limits...
        
        	if { ( [string tolower [HTTP::path]] equals "/login" )
        	 and ( [HTTP::method] equals "POST" )
        	 and ( [HTTP::header value "Content-Length"] ne "" )
        	 and ( [HTTP::header value "Content-Length"] < $static::max_payload_size ) } then {
        
        		# Collect the HTTP payload and trigger HTTP_REQUEST_DATA event
        		
        		HTTP::collect [HTTP::header value "Content-Length"]
        
        	}
        
        }
        when HTTP_REQUEST_DATA {
        
        	# Define the input used for HMAC signing
        
        	set temp(hmac_input) [HTTP::payload]
        
        	# Compute the HMAC checksum for the input using our secret key
        
        	set temp(hmac_output) [b64encode [CRYPTO::sign -alg hmac-sha256 -key $static::hmac_key $temp(hmac_input)]]
        
        	# Contruct the new payload
        
        	set temp(new_payload) "[string trimright [HTTP::payload] "\}"],\"hashsha256\":\"$temp(hmac_output)\"\}"
        
        	# Replace the payload	
        
        	HTTP::payload replace 0 [HTTP::payload length] $temp(new_payload)
        
        	unset -nocomplain temp
        
        }

         

        At later stage we may or may not combine those 4 logical steps into a single syntax line, to reduce processing overhead to a minimum.. 😉

         

        when HTTP_REQUEST_DATA {
        	
        	# Replace the payload with HMAC signed payload...
        
        	HTTP::payload replace 0 [HTTP::payload length] "[string trimright [HTTP::payload] "\}"],\"hashsha256\":\"[b64encode [CRYPTO::sign -alg hmac-sha256 -key $static::hmac_key [HTTP::payload]]]\"\}"
        	
        }

         

        Cheers, Kai