Skip to content

Secure API

muraliens edited this page Jan 31, 2024 · 3 revisions

Secure API

Some critical application needs more protection than the normal tls/ssl. This option will facilate Client & Server to have addtional security by wrapping orginal json object using the shared secret.

How to enable

This option is easy to enable by passing the server options during the initialization.

// pk -> ecdh private key, to pass nil to generate automatically
// licenseKey -> License key will checked by server, client has to send the license key in the 'licensekey' header in every request
s, err := ensweb.NewServer(cfg, nil, log, ensweb.EnableSecureAPI(pk, licenseKey))

Easy to parse the orginal json object on the handle function, parse json function will automatically unwrap json and provide the orginal module, returns error in case of any error in unwrapping.

// Orginal JSON request module
var lr LoginRequest
err := s.ParseJSON(req, &lr)

Similarly it is easy to render orignal json object to the client, render json function will automatically wrap json and provide wrapped json object to client.

// Orginal JSON request module
var lr LoginResponse
// ... 
return s.RenderJSON(req, lr, http.StatusOK)

How this work

Server

The following header should present in every REST API request

  • licensekey - client should send the proper license key
  • publickey - public key of the client encoded in the base64 format
  • requestid - request id object is wrapped and encoded in the base64 format

Resuet ID Model

{
    "uuid" : "xxxx-xxxx"
	"journeyId": "xxxx-xxxx"
	"ts": 12829101
	"appid": "goclient"
}

Server extract the public key from the header & using his private key generates the shared secret. Uses Wrap & UnWrap functions to send & receive json objects.

Client

Client will get the server public key using the following endpoint /api/getpublickey

Reponse
{
    "status" : true,
    "message" : "server public key",
    "publicKey": "Essjdkskdjskjd"
}

Using his private key generates the shared secret. Uses Wrap & UnWrap functions to send & receive json objects.

Pseudo Functions

genshared-secret(publickey, shared-secret) {
    // ECDH p256 used for shared secret generation
    pub = base64.decode(publickey)
    pk = get_privkey() // local private key
    ss = pk.ECDH (pub)
    hs = sha256(ss)
    shared-secret = hex.encode(hs)
}

genkey(shared-secret) {
    return sha256(shared-secret)
}

wrap(shared-secret, in_object, out_object) {
    data = jsonmarshal(in_object) // serialize

    key = genkey(shared-secret)

    aes = AES(key)

    gcm = GCM(aes)

    nonce = GenerateRand(gcm.NonceSize())
    
    enc_data = gcm.Seal(nonce, nonce, data) 
    // enc_data = (nonce, cipher_data)

    // json object
    out_object = {
        "data" : base64.encode(enc_data)
    }
}

unwrap(shared-secret, in_object, out_object) {
    enc_data = base64.decode(in_object["data"])

    key = genkey(shared-secret)

    aes = AES(key)

    gcm = GCM(aes)

    nonce, cipher_data = enc_data
    
    dec_data = gcm.UnSeal(nonce, cipher_data)

    out_object = jsonunmarshal(dec_data) // deserialize
}

Clone this wiki locally