|
|
|
package main
|
|
|
|
|
|
|
|
// crypt.go: various cryptographical operations
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/hmac"
|
|
|
|
cryptoRand "crypto/rand"
|
|
|
|
"crypto/sha1"
|
|
|
|
"crypto/sha256"
|
|
|
|
mathRand "math/rand"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
registerSwitch("crypt-predictable-rng", "disable secure rng and use a pseudorandom preseeded rng")
|
|
|
|
mathRand.Seed(300)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSHA1Digest(data []byte) []byte {
|
|
|
|
array := sha1.Sum(data)
|
|
|
|
return array[:]
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSHA2Digest(data []byte) []byte {
|
|
|
|
array := sha256.Sum256(data)
|
|
|
|
return array[:]
|
|
|
|
}
|
|
|
|
|
|
|
|
func HKDF(data []byte) []byte {
|
|
|
|
h := hmac.New(sha1.New, []byte(strings.Repeat("\x00", 64)))
|
|
|
|
h.Write(data)
|
|
|
|
h1 := h.Sum(nil)
|
|
|
|
h2 := make([]byte, 0)
|
|
|
|
res := make([]byte, 0)
|
|
|
|
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
h = hmac.New(sha1.New, h1)
|
|
|
|
h.Write(h2)
|
|
|
|
h.Write([]byte{byte(i) + 1})
|
|
|
|
h2 = h.Sum(nil)
|
|
|
|
res = append(res, h2...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return res[:0x24]
|
|
|
|
}
|
|
|
|
|
|
|
|
func genStreamKeys(server bool, data []byte) (sendAESKey, sendHMACKey, receiveAESKey, receiveHMACKey []byte) {
|
|
|
|
const magic2 = "On the client side, this is the send key; on the server side, it is the receive key."
|
|
|
|
const magic3 = "On the client side, this is the receive key; on the server side, it is the send key."
|
|
|
|
|
|
|
|
var txEnc, rxEnc []byte
|
|
|
|
|
|
|
|
txEnc = append(data, []byte(strings.Repeat("\x00", 40))...)
|
|
|
|
rxEnc = append(data, []byte(strings.Repeat("\x00", 40))...)
|
|
|
|
|
|
|
|
if server {
|
|
|
|
txEnc = append(txEnc, magic3...)
|
|
|
|
rxEnc = append(rxEnc, magic2...)
|
|
|
|
} else {
|
|
|
|
txEnc = append(txEnc, magic2...)
|
|
|
|
rxEnc = append(rxEnc, magic3...)
|
|
|
|
}
|
|
|
|
|
|
|
|
txEnc = append(txEnc, []byte(strings.Repeat("\xF2", 40))...)
|
|
|
|
rxEnc = append(rxEnc, []byte(strings.Repeat("\xF2", 40))...)
|
|
|
|
|
|
|
|
txEnc = getSHA1Digest(txEnc)[:16]
|
|
|
|
rxEnc = getSHA1Digest(rxEnc)[:16]
|
|
|
|
|
|
|
|
sendKey := HKDF(txEnc)
|
|
|
|
sendAESKey = sendKey[:16]
|
|
|
|
sendHMACKey = sendKey[16:]
|
|
|
|
|
|
|
|
receiveKey := HKDF(rxEnc)
|
|
|
|
receiveAESKey = receiveKey[:16]
|
|
|
|
receiveHMACKey = receiveKey[16:]
|
|
|
|
|
|
|
|
return sendAESKey, sendHMACKey, receiveAESKey, receiveHMACKey
|
|
|
|
}
|
|
|
|
|
|
|
|
func genPasswordValidatorPriv(username, password string, salt []byte) []byte {
|
|
|
|
if len(salt) != 16 {
|
|
|
|
panic("salt must be 16 bytes")
|
|
|
|
}
|
|
|
|
|
|
|
|
hash := getSHA2Digest([]byte(username + ":" + password))
|
|
|
|
return getSHA2Digest(append(salt, hash...))
|
|
|
|
}
|
|
|
|
|
|
|
|
func genRandomBytes(n int) ([]byte, error) {
|
|
|
|
b := make([]byte, n)
|
|
|
|
|
|
|
|
var err error
|
|
|
|
if getParamSwitch("crypt-predictable-rng") {
|
|
|
|
_, err = mathRand.Read(b)
|
|
|
|
} else {
|
|
|
|
_, err = cryptoRand.Read(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return b, nil
|
|
|
|
}
|