Golang signing with a public key

185 Views Asked by At

Can anyone suggest a way of modifying the below code so that I can use the constant pubkey I've included? I'm having trouble changing it and getting it to work with a constant.

package main
import (
    "golang.org/x/crypto/nacl/sign"
    "crypto/rand"
    "log"
    "encoding/base64"
    "encoding/json"
    "io/ioutil"
    "net/http"
"github.com/gin-gonic/gin"
// "os"
// "strings"

)

type authtoken struct {
    Cookie  string  `json:"cookie"`
}


type user struct {
    Username  string  `json:"username"`
    Password string  `json:"password"`
}

var users []user

var pubkey *[64]byte
var privkey *[32]byte

const pubkeyStr = "123eRhvE0bqx81t3G9o79LOkkR4CK9Cyhvt8-QJ-s1H2A6uSwukUI0CYUlc3WbmIAa3VTo4Jm9RF5F0Af4DzmQ"

func login(c *gin.Context) {
    var tryUser user
    if err := c.BindJSON(&tryUser); err != nil {
        return
    }

    for _, user := range users {
        if user == tryUser {
            // Convert the constant public key string to bytes
            pubkey := []byte(pubkeyStr)
            //token = authtoken{Username: user.Username}
            //out := make([]byte, 300)
            out := make([]byte,0)
            log.Println("username", []byte(user.Username), "pubkey",pubkey)
            signedtokenout := sign.Sign(out, []byte(user.Username), pubkey)
            log.Println("signed token:",signedtokenout)
            signedtokenstr := base64.RawURLEncoding.EncodeToString(signedtokenout[:])
            c.IndentedJSON(http.StatusOK, gin.H{"cookie":signedtokenstr})
            c.IndentedJSON(http.StatusOK, gin.H{"my pubkey is":base64.RawURLEncoding.EncodeToString(pubkey[:])})
            return
    }
}
c.IndentedJSON(http.StatusForbidden, "wrong")

}

func home(c *gin.Context) {
    c.IndentedJSON(http.StatusOK, gin.H{"my pubkey is":base64.RawURLEncoding.EncodeToString(pubkey[:])})
}

func main() {

    bytes, err := ioutil.ReadFile("users.json")
    if err != nil {
    log.Println("Unable to load users file!")
    return
    }
    err = json.Unmarshal(bytes, &users)
    if err != nil {
        log.Println("Unable to unmarshal users file!")
        return
    }


    privkey,pubkey, _ = sign.GenerateKey(rand.Reader)
    // if err != nil {
    //      log.Fatal("could not GenerateKey", err)
    // }
    log.Printf("\n\nThe public key is:%v\n\nThe private key is:%v\n", pubkey,privkey)

    pubstr := base64.RawURLEncoding.EncodeToString(pubkey[:])
log.Println("\nThe encoded public key:", pubstr)

router := gin.Default()

router.POST("/login", login)
router.GET("/", home)

router.Run("0.0.0.0:80")

}

I want to be able to replace "var pubkey *[64]byte" with the constant pubkey in the entire code. At the moment, when running it, it generates a random key in the main function which is currently expected, but not what I need. I have an idea that the 'type' is incorrect but I can't work out how to modify it.

Any assistance would be greatly appreciated.

UPDATE - I've made progress thanks to @larsks by implementing your code.

I get the use of a constant key however what I have now realised is that the cookie created during the login process is a signed token using the base64 encoded string, therefore the string I am setting as the constant, is not the actual string I want to use.

My goal is to able able to reverse eng the cookie using the username, knowing that it's been signed with the key.

Essentially, if I have a cookie in the form P5Q-c_EQWhkUbagDC3klwsv0SQ6JdK9zDZLws3PzWjjdjcqiHlJMWLsxKDraTgU6za_fOXuaEOa5i2NhEmY0DnJvY2t5 , where the username is rocky, I want to modify the cookie and use the username 'admin' knowing the encoded pubkey is 123eRhvE0bqx81t3G9o79LOkkR4CK9Cyhvt8-QJ-s1H2A6uSwukUI0CYUlc3WbmIAa3VTo4Jm9RF5F0Af4DzmQ

That said, there might be an easier way to do this so I am open to suggestions.

I have tried this as a complete left of arc trial but I'm noticing the modified cookie has a different length to the original.

package main

import (
    "encoding/base64"
    "fmt"
    "log"
)

type User struct {
    Username string
}

func main() {
    // Your original public key value
    pubkeyStr := "937eRhvE0bqx81t3G9o79LOkkR4CK9Cyhvt8-QJ-s1H2A6uSwukUI0CYUlc3WbmIAa3VTo4Jm9RF5F0Af4DzmQ"
    pubkey, err := base64.RawURLEncoding.DecodeString(pubkeyStr)
    if err != nil {
        log.Fatal("Error decoding public key:", err)
    }

    // Existing cookie value
    existingCookie := "P5Q-c_EQWhkUbagDC3klwsv0SQ6JdK9zDZLws3PzWjjdjcqiHlJMWLsxKDraTgU6za_fOXuaEOa5i2NhEmY0DnJvY2t5"

    Username := "admin"

    // Modify the existing cookie to change the username
    modifiedCookie, err := modifyCookie(existingCookie, Username, pubkey)
    if err != nil {
        log.Fatal("Error modifying cookie:", err)
    }

    fmt.Println("Encoded public key used is:", pubkeyStr)
    fmt.Println("\nDecoded public key is   :", pubkey)
    fmt.Println("\nCookie to be modified is:", existingCookie)
    fmt.Println("\nModified Cookie is      :", modifiedCookie)
//    fmt.Println("Or is this the modified cookie:", modifiedCookieStr)
    fmt.Println("\nEncoded public key should be 937eRhvE0bqx81t3G9o79LOkkR4CK9Cyhvt8-QJ-s1H2A6uSwukUI0CYUlc3WbmIAa3VTo4Jm9RF5F0Af4DzmQ")
    fmt.Println("\nRencoded public key, to ensure integirty, is:", base64.RawURLEncoding.EncodeToString(pubkey))
}

// Dummy function to modify the existing cookie
func modifyCookie(existingCookie string, Username string, pubkey []byte) (string, error) {

    // Decode the existing cookie from base64
    decodedCookie, err := base64.RawURLEncoding.DecodeString(existingCookie)
    if err != nil {
        return "", err
    }

    // Verify the signature of the existing cookie
    if err := verifySignature(decodedCookie, pubkey); err != nil {
        return "", err
    }

    // Modify the username
    userPart := decodedCookie[:len(decodedCookie)-len(pubkey)]
    modifiedCookie := append(userPart, []byte(Username)...)
    modifiedCookie = append(modifiedCookie, pubkey...)

    // Encode the modified cookie back to base64
    modifiedCookieStr := base64.RawURLEncoding.EncodeToString(modifiedCookie)

    return modifiedCookieStr, nil
}

// Dummy function to verify the signature of the existing cookie
func verifySignature(cookie []byte, pubkey []byte) error {
    // Replace this with your actual logic to verify the cookie signature
    // For security, you should use a proper cryptographic library
    // This is just a dummy example
    return nil
}
1

There are 1 best solutions below

4
larsks On

I want to be able to replace var pubkey *[64]byte with the constant pubkey in the entire code.

I don't think you can do that exactly, but you could initialize a global variable in init:

var pubkey *[64]byte
const pubkeyStr = "123eRhvE0bqx81t3G9o79LOkkR4CK9Cyhvt8-QJ-s1H2A6uSwukUI0CYUlc3WbmIAa3VTo4Jm9RF5F0Af4DzmQ"

func init() {
  pubkey = &[64]byte{}
  copy(pubkey[:], pubkeyStr)
}

With that, you can reference pubkey anywhere else in your package and it will have the expected value.