Skip to content

Instantly share code, notes, and snippets.

@inhies
Created March 25, 2013 18:41
Show Gist options
  • Save inhies/5239492 to your computer and use it in GitHub Desktop.
Save inhies/5239492 to your computer and use it in GitHub Desktop.
Generates the important bits of a cjdns configuration file and outputs it as JSON.
package main
import (
"code.google.com/p/go.crypto/curve25519"
"crypto/rand"
"crypto/sha512"
"encoding/json"
"fmt"
mathrand "math/rand"
"runtime"
"strconv"
"time"
)
const (
jsonSpacer = "\t" // Character(s) to use for indenting JSON output
bindIP = "0.0.0.0" // Bind IP address
bindPortMin = 10000 // Minimum port to use for the bind field
bindPortMax = 19999 // Maximum port to use for the bind field
adminBind = "127.0.0.1:11234" // IP and port for the admin interface to bind to
version = "2012.03.25.1" // Program version
)
// How many cores or processing units do you want to use.
// The default is all of them for maximum speed.k
var useCPUs = runtime.NumCPU()
type KeyPair struct {
Private [32]byte
Public [32]byte
IP string
}
type Output struct {
PrivateKey string `json:"privateKey"`
PublicKey string `json:"publicKey"`
IPv6 string `json:"ipv6"`
Bind string `json:"bind"`
Admin adminBlock `json:"admin"`
}
type adminBlock struct {
Password string `json:"password"`
Bind string `json:"bind"`
}
func init() {
runtime.GOMAXPROCS(useCPUs)
mathrand.Seed(time.Now().UTC().UnixNano())
}
func main() {
data := MakeKeyPair()
output := &Output{}
output.PrivateKey = fmt.Sprintf("%x", data.Private[:])
output.PublicKey = string(EncodePubKey(data.Public[:])) + ".k"
output.IPv6 = data.IP
output.Admin.Password = randString(15, 50)
output.Admin.Bind = adminBind
output.Bind = bindIP + ":" + strconv.Itoa(bindPortMin+mathrand.Intn(bindPortMax-bindPortMin))
jsonout, err := json.MarshalIndent(output, "", jsonSpacer)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(jsonout))
}
// Returns a random alphanumeric string where length is <= max >= min
func randString(min, max int) string {
r := myRand(min, max, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
return r
}
// Returns a random character from the specified string where length is <= max >= min
func myRand(min, max int, char string) string {
var length int
if min < max {
length = min + mathrand.Intn(max-min)
} else {
length = min
}
buf := make([]byte, length)
for i := 0; i < length; i++ {
buf[i] = char[mathrand.Intn(len(char)-1)]
}
return string(buf)
}
// base32 encodes the public key for use in the decoder
func EncodePubKey(in []byte) (out []byte) {
var wide, bits uint
var i2b = []byte("0123456789bcdfghjklmnpqrstuvwxyz")
for len(in) > 0 {
// Add the 8 bits of data from the next `in` byte above the existing bits
wide, in, bits = wide|uint(in[0])<<bits, in[1:], bits+8
for bits > 5 {
// Remove the least significant 5 bits and add their character to out
wide, out, bits = wide>>5, append(out, i2b[int(wide&0x1F)]), bits-5
}
}
// If it wasn't a precise multiple of 40 bits, add some padding based on the remaining bits
if bits > 0 {
out = append(out, i2b[int(wide)])
}
return out
}
// Will loop until a valid keypair is found
func MakeKeyPair() (key KeyPair) {
random := key.Private[:]
Start:
rand.Read(random)
key.Private[0] &= 248
key.Private[31] &= 127
key.Private[31] |= 64
curve25519.ScalarBaseMult(&key.Public, &key.Private)
// Do the hashing that generates the IP
out := sha512hash(sha512hash(key.Public[:]))
if out[0] != 0xfc {
goto Start
}
// Assemble the IP
out = out[0:16]
for i := 0; i < 16; i++ {
if i > 0 && i < 16 && i%2 == 0 {
key.IP += ":"
}
key.IP += fmt.Sprintf("%02x", out[i])
}
return
}
func sha512hash(input []byte) []byte {
h := sha512.New()
h.Write(input)
return []byte(h.Sum(nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment