tsdeclarations icon indicating copy to clipboard operation
tsdeclarations copied to clipboard

How can I confirm the servers calculated public key?

Open schoeppi5 opened this issue 3 years ago • 1 comments

I am currently implementing the last step of the crypto handshake and am kinda stuck on the clientek command. When I send it, it isn't being acknowledged. This means to me, that something went wrong on my side with calculating the servers public key (or the shared secret, but that part is rather straight forward from an implementations point of view).

I am not entierly sure, how to go about calulating the server's public key. This far I have the following go code:

func (l *License) serverPublicKey() ([]byte, error) {
    parent := rootKey
    for i := range l.Blocks { // iterate over the licenses blocks
        hash := sha512.Sum512(l.Blocks[i].Bytes()[1:])
        privateKey := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
        publicKey := &edwards25519.Point{}.SetBytes(l.Blocks[i].PublicKey)
        next := &edwards25519.Point{}.ScalarMult(privateKey, publicKey)
        parent = next.Add(next, parent)
    }
    return parent.BytesMontgomery(), nil
}

I guess, you might not be an golang expert, but what I am basically doing here is:

  • Get the rootKey as an edwards25519 Point
  • iterate over the license blocks
  • calculate the (64 bytes long) sha512 hash of the block except the first byte
  • get the private key as a edwards25519 scalar using the first 32 bytes of the hash
  • get the public key as a edwards25519 point
  • calculate the point of publicKey * privateKey (point * scalar) as next
  • set the parent to next + parent
  • after the loop: return parent as bytes on the montgomery curve. I guess I have to do that, since edwards25519 != curve25519, but curve25519 is a montgomery curve so this should account for that (https://pkg.go.dev/filippo.io/edwards25519#Point.BytesMontgomery)

Am I doing something fundamentaly wrong here?

Btw: This is how I calculate the shared secret:

func sharedSecret(serverPublicKey []byte, alpha []byte, beta []byte) (sharedIV [64]byte, sharedMAC [8]byte, tempPublicKey []byte) {
    tempPrivateKey := edwards25519.NewScalar().SetBytesWithClamping(randomByteArray(length: 32))
    tempPublicKey := &edwards25519.Point{}.ScalarBaseMult(tempPrivateKey).Bytes()
    
    serverPub := &edwards25519.Point{}.SetBytes(serverPublicKey)
    sharedData := serverPub.ScalarMult(tempPrivateKey, serverPub)
    sharedIV = sha512.Sum512(sharedData.BytesMontgomery()[:32])

    // xor alpha
    for i := range alpha {
        sharedIV[i] ^= alpha[i]
    }
    // xor beta
    for i := range beta {
       sharedIV[10+i] ^= beta[i]
    }
    sharedMAC := sha1.Sum(sharedIV)[:8]
    return sharedIV, sharedMAC, tempPublicKey
}

Again: anything fundamentaly wrong here?

Thanks for any help you might be able to offer. I don't really know how I can debug that, hence my question: How can I check as a first step, if my calculated server public key is correct?

MfG

schoeppi5 avatar Feb 23 '21 09:02 schoeppi5

Hi, I have to say the same as on #61, I don’t see anything wrong with the code you posted. We have a testcase that might be helpful, you can compare your results with the results here: https://github.com/ReSpeak/tsclientlib/blob/4d08aaa77e94ec385b562e48310d270722adf517/tsproto/src/algorithms.rs#L317-L397

If the results are different, you can try to compare the results of each step with one of the existing implementations (tsclientlib, TS3AudioBot or ts3j).

Flakebi avatar Feb 25 '21 20:02 Flakebi