Generating CHAP response for teltonika routers in golang

What were you doing

I’ve been developing a hotspot portal solution in golang for the better part of two years.

One may ask why another hotspot system and i would answer that with another question, how stable is your network in your country?. This hotspot solution is designed to withstand bad network latencies and connectivity in countries where the neccessary facilities to run a smooth network based solution dont exist or are mismanaged.

This is specific to most African countries and i just happen to be developing this solution in and for one of them.

Since this is a hotspot system, i had to make it compatible with various AP/Routers which include nodogsplash linux based ALIX routers, chillispot ruckus AP’s, mikrotik routers, teltonika RUT955 router and other types.

Why CHAP passwords

Recently, why integrating the Teltonika RUT955 i ran into a bit of trouble with generating a CHAP response for clients authenticating to a Radius server. I wouldn’t like to go into what CHAP responses are and why you need them for secure radius client authentications, lets leave that to this wikipedia entry, https://en.wikipedia.org/wiki/Challenge-Handshake_Authentication_Protocol.

I’m no newbie to PHP programming language but it is my least favourite language which made this issue a bit frustrating. I had to reimplement the follwing snippet, from https://community.teltonika.lt/2972/how-to-authenticate-from-external-landing-page-hotspot-mode, in golang. This snippet generates a valid CHAP response.

 <?
    $password   = "432768ec1d";
    $challenge  = "a1501e8bb2701d3d9b535594993f67a7";
    $hexchal = pack ("H32", $challenge);
    $response = md5("\0" . $password . $hexchal);
    echo $response;
    //201089abdf8683ab52f37ee9eb0ab68e
 ?>

Let’s see how this is done in golang.

package main

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
)

 func main() {
    password := "432768ec1d"
    challenge := "a1501e8bb2701d3d9b535594993f67a7"
    hexchal, _ := hex.DecodeString(challenge)
    fmt.Printf("%x", md5.Sum([]byte(fmt.Sprintf("%s%s%s", "\x00", password, string(hexchal)))))
    //201089abdf8683ab52f37ee9eb0ab68e
}

This doesn’t look overly complicated however, this took me two days to figure out. It was mostly due to the fact that i had lost touch with golang basics which led to me digging into the docs to learn some facts about bytes once more.

I had help from this post https://stackoverflow.com/questions/38007361/is-there-anyway-to-create-null-terminated-string-in-go I hope this helps someone.