Encryption/decryption schemes are of limited use if you have to do all the heavy lifting yourself. The most popular mechanism on the internet to give support for encrypted message passing is currently TLS (Transport Layer Security) which was formerly SSL (Secure Sockets Layer).
In TLS, a client and a server negotiate identity using X.509 certificates. Once this is complete, a secret key is invented between them, and all encryption/decryption is done using this key. The negotiation is relatively slow, but once complete a faster private key mechanism is used.
A server is
/* TLSEchoServer
*/
package main
import (
"crypto/rand"
"crypto/tls"
"fmt"
"net"
"os"
"time"
)
func main() {
cert, err := tls.LoadX509KeyPair("jan.newmarch.name.pem", "private.pem")
checkError(err)
config := tls.Config{Certificates: []tls.Certificate{cert}}
now := time.Now()
config.Time = func() time.Time { return now }
config.Rand = rand.Reader
service := "0.0.0.0:1200"
listener, err := tls.Listen("tcp", service, &config)
checkError(err)
fmt.Println("Listening")
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(err.Error())
continue
}
fmt.Println("Accepted")
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
var buf [512]byte
for {
fmt.Println("Trying to read")
n, err := conn.Read(buf[0:])
if err != nil {
fmt.Println(err)
}
_, err2 := conn.Write(buf[0:n])
if err2 != nil {
return
}
}
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error ", err.Error())
os.Exit(1)
}
}
The server works with the following client:
/* TLSEchoClient
*/
package main
import (
"fmt"
"os"
"crypto/tls"
)
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: ", os.Args[0], "host:port")
os.Exit(1)
}
service := os.Args[1]
conn, err := tls.Dial("tcp", service, nil)
checkError(err)
for n := 0; n < 10; n++ {
fmt.Println("Writing...")
conn.Write([]byte("Hello " + string(n+48)))
var buf [512]byte
n, err := conn.Read(buf[0:])
checkError(err)
fmt.Println(string(buf[0:n]))
}
os.Exit(0)
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error ", err.Error())
os.Exit(1)
}
}
Security is a huge area in itself, and in this chapter we have barely touched on it. However, the major concepts have been covered. What has not been stressed is how much security needs to be built into the design phase: security as an afterthought is nearly always a failure.