Encrypting and Decrypting JwtToken in rails application with HS256(HMAC) and RS256(RSA) algorithms.

Understanding jwt, HS256 and RS256 algorithms.

Shashwat Srivastava
3 min readJul 7, 2019

So, what is jwt token?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Key point: JWT is used for securely transmitting the information as a JSON object.

How to use it in rails application?

Installation Using RubyGems:

sudo gem install jwt

Installation Using Bundler:

Add the following to your Gemfile

gem 'jwt'

And run bundle install

Usage

Jwt gem supports NONE, HMAC, RSASSA and ECDSA algorithms for cryptographic signing. If we look at the sign method of jwt in

"/.rvm/gems/ruby-#{version}/gems/jwt-#{version}/lib/jwt.rb"

we can see that HS256 and RS256 are signed with HMAC and RSA algorithms respectively.

def sign(algorithm, msg, key)
if %w(HS256 HS384 HS512).include?(algorithm)
sign_hmac(algorithm, msg, key)
elsif %w(RS256 RS384 RS512).include?(algorithm)
sign_rsa(algorithm, msg, key)
elsif %w(ES256 ES384 ES512).include?(algorithm)
sign_ecdsa(algorithm, msg, key)
else
raise NotImplementedError, 'Unsupported signing method'
end
end

create a module in your utils directory, let’s name it jwt_utils.
path — lib/utils/jwt_utils.rb

module JwtUtils
require 'jwt'
def self.encrypt(payload, salt, algo = 'HS256')
JWT.encode payload, salt, algo
end
def self.decrypt(token, salt, algo = 'HS256')
decrypted_token = JWT.decode token, salt, algo
decrypted_token.first.deep_symbolize_keys rescue {}
end
end

let’s define our payload:

payload = { user: ‘test’, mobile_number: ‘XXXXXXXXXX’}

Now, create a project_util.rb file.

HS256 algorithm: HS256 (HMAC with SHA-256), is a symmetric(i.e single key) algorithm, with only one (secret) key that is shared between the two parties. Since the same key is used both to generate the signature and to validate it, care must be taken to ensure that the key is not compromised.

module ProjectUtils
require 'utils/jwt_utils'
def self.encrypt(payload)
JwtUtils.encrypt(payload, "hmac_secret_key", "HS256")
end
def self.decrypt(token)
JwtUtils.decrypt(token, "hmac_secret_key", "HS256")
end
end

to encrypt just call the encrypt method with a payload

2.6.2 :001 > token = ProjectUtils.encrypt(payload)
=> “eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoidGVzdCIsIm1vYmlsZV9udW1iZXIiOiJYWFhYWFhYWFhYIn0.wl6ewn8Y9i4VVIjdG4bGL3WAA_Lx582R7DI5ilgazNM”

we can also add a timeout for jwt token in the payload at the time of encrypting.

JwtUtils.encrypt(payload.merge(exp: 5.minutes.from_now.to_i), "hmac_secret_key", "HS256")

while decrypting just call decrypt method with the token

2.6.2 :005 > ProjectUtils.decrypt(token)
=> {:user=>”test”, :mobile_number=>”XXXXXXXXXX”}

we can keep the “hmac_secret_key” in a config/config.json file.

RS256 algorithm: RS256 (RSA Signature with SHA-256) is an asymmetric(i.e different keys for encrypting and decrypting) algorithm, and it uses a public/private key pair: the sender has a private key of the receiver which is used to encrypt data and it could only be decrypted by receivers public key.

module ProjectUtils
require 'utils/jwt_utils'
def self.encrypt(payload)
private_key = OpenSSL::PKey::RSA.new(PRIVATE_KEY.gsub("\\n", "\n"))
JwtUtils.encrypt(payload, private_key, 'RS256')
end
def self.decrypt(token)
rsa_public_key = OpenSSL::PKey::RSA.new(public_key)
JwtUtils.decrypt(token, rsa_public_key, 'RS256')
end
end

PRIVATE_KEY, PUBLIC_KEY should be config based and can be generated by the following steps:

1. ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
2. openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub
3. cat jwtRS256.key . # get private key
4. cat jwtRS256.key.pub # get public key

Note: Once sender encrypts the data even sender cannot decrypt it without the public key of receiver.

************************* THANK YOU **************************

If you are looking for more details on JwtToken have a look at this document https://github.com/jwt/ruby-jwt

--

--