Last active
October 17, 2017 23:46
-
-
Save rickcrawford/a73a9ed33b8ef02d16cef5a526980fea to your computer and use it in GitHub Desktop.
AES encryption example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/tls" | |
"fmt" | |
"log" | |
"net" | |
"net/http" | |
"os" | |
"os/signal" | |
"sync" | |
"syscall" | |
"time" | |
) | |
// Loads certificate automagically | |
type keypairReloader struct { | |
certMu sync.RWMutex | |
cert *tls.Certificate | |
certPath string | |
keyPath string | |
} | |
func NewKeypairReloader(certPath, keyPath string) (*keypairReloader, error) { | |
result := &keypairReloader{ | |
certPath: certPath, | |
keyPath: keyPath, | |
} | |
cert, err := tls.LoadX509KeyPair(certPath, keyPath) | |
if err != nil { | |
return nil, err | |
} | |
result.cert = &cert | |
go func() { | |
c := make(chan os.Signal, 1) | |
signal.Notify(c, syscall.SIGHUP) | |
for range c { | |
log.Printf("Received SIGHUP, reloading TLS certificate and key from %q and %q", certPath, keyPath) | |
if err := result.maybeReload(); err != nil { | |
log.Printf("Keeping old TLS certificate because the new one could not be loaded: %v", err) | |
} | |
} | |
}() | |
return result, nil | |
} | |
func (kpr *keypairReloader) maybeReload() error { | |
newCert, err := tls.LoadX509KeyPair(kpr.certPath, kpr.keyPath) | |
if err != nil { | |
return err | |
} | |
kpr.certMu.Lock() | |
defer kpr.certMu.Unlock() | |
kpr.cert = &newCert | |
return nil | |
} | |
func (kpr *keypairReloader) GetCertificateFunc() func(*tls.ClientHelloInfo) (*tls.Certificate, error) { | |
return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { | |
kpr.certMu.RLock() | |
defer kpr.certMu.RUnlock() | |
return kpr.cert, nil | |
} | |
} | |
type Certificates struct { | |
CertFile string | |
KeyFile string | |
} | |
func ListenAndServeTLSSNI(srv *http.Server, certs []Certificates) error { | |
addr := srv.Addr | |
if addr == "" { | |
addr = ":443" | |
} | |
config := &tls.Config{ | |
MinVersion: tls.VersionTLS12, | |
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, | |
PreferServerCipherSuites: true, | |
CipherSuites: []uint16{ | |
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | |
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, | |
tls.TLS_RSA_WITH_AES_256_GCM_SHA384, | |
tls.TLS_RSA_WITH_AES_256_CBC_SHA, | |
// curl uses below | |
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | |
}, | |
} | |
if config.NextProtos == nil { | |
config.NextProtos = []string{"h2", "http/1.1"} | |
} | |
var err error | |
config.InsecureSkipVerify = false | |
config.Certificates = make([]tls.Certificate, len(certs)) | |
for i, v := range certs { | |
config.Certificates[i], err = tls.LoadX509KeyPair(v.CertFile, v.KeyFile) | |
if err != nil { | |
return err | |
} | |
} | |
// kpr, err := NewKeypairReloader(*tlsCertPath, *tlsKeyPath) | |
// if err != nil { | |
// log.Fatal(err) | |
// } | |
// srv.TLSConfig.GetCertificate = kpr.GetCertificateFunc() | |
config.BuildNameToCertificate() | |
conn, err := net.Listen("tcp", addr) | |
if err != nil { | |
return err | |
} | |
tlsListener := tls.NewListener(conn, config) | |
return srv.Serve(tlsListener) | |
} | |
func main() { | |
var run = func() *http.Server { | |
srv := &http.Server{ | |
ReadTimeout: 5 * time.Second, | |
WriteTimeout: 10 * time.Second, | |
} | |
var certs []Certificates | |
certs = append(certs, Certificates{ | |
CertFile: "etc/site1.pem", | |
KeyFile: "etc/site1.key", | |
}) | |
certs = append(certs, Certificates{ | |
CertFile: "etc/site2.pem", | |
KeyFile: "etc/site2.key", | |
}) | |
fmt.Println("Listening on port 443...") | |
go func() { | |
err := ListenAndServeTLSSNI(srv, certs) | |
if err != nil { | |
fmt.Printf("-->err: %s\n", err) | |
} | |
}() | |
return srv | |
} | |
s := run() | |
signalChan := make(chan os.Signal, 1) | |
signal.Notify(signalChan, syscall.SIGHUP) | |
for _ = range signalChan { | |
fmt.Println("Received an interrupt, stopping services...") | |
s.Close() | |
s = run() | |
} | |
// for _ = range c { | |
// w.WriteString("Received sighup\n") | |
// w.Flush() | |
// run() | |
// } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://play.golang.org/p/2XZp3CRbGu | |
package main | |
import ( | |
"crypto/aes" | |
"crypto/cipher" | |
"crypto/rand" | |
"encoding/base64" | |
"fmt" | |
"io" | |
) | |
const ck = "AES256Key-32Characters1234567890" | |
func ExampleNewGCMEncrypter(s string) string { | |
// The key argument should be the AES key, either 16 or 32 bytes | |
// to select AES-128 or AES-256. | |
key := []byte(ck) | |
plaintext := []byte(s) | |
block, err := aes.NewCipher(key) | |
if err != nil { | |
panic(err.Error()) | |
} | |
// Never use more than 2^32 random nonces with a given key because of the risk of a repeat. | |
nonce := make([]byte, 12) | |
if _, err := io.ReadFull(rand.Reader, nonce); err != nil { | |
panic(err.Error()) | |
} | |
// fmt.Printf("%x\n", nonce) | |
aesgcm, err := cipher.NewGCM(block) | |
if err != nil { | |
panic(err.Error()) | |
} | |
ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil) | |
str := base64.StdEncoding.EncodeToString(append(nonce, ciphertext...)) | |
fmt.Printf("%s\n", str) | |
return str | |
} | |
func ExampleNewGCMDecrypter(s string) { | |
// The key argument should be the AES key, either 16 or 32 bytes | |
// to select AES-128 or AES-256. | |
key := []byte(ck) | |
data, _ := base64.StdEncoding.DecodeString(s) | |
nonce := data[:12] | |
ciphertext := data[12:] | |
block, err := aes.NewCipher(key) | |
if err != nil { | |
panic(err.Error()) | |
} | |
aesgcm, err := cipher.NewGCM(block) | |
if err != nil { | |
panic(err.Error()) | |
} | |
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) | |
if err != nil { | |
panic(err.Error()) | |
} | |
fmt.Printf("%s\n", plaintext) | |
// Output: exampleplaintext | |
} | |
func main() { | |
s := ExampleNewGCMEncrypter("asdf 1234 asdf 1234 asdf 1234 asdf 1234 asdf 1234\nasdf 1234 asdf 1234 asdf 1234 asdf 1234 asdf 1234\nasdf 1234 asdf 1234 !!") | |
ExampleNewGCMDecrypter(s) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Couple examples - One does AES encryption/decryption, then a library that allows me to do SNI based certificates with the cert values encrypted. I wrote a proxy that supports multiple domains, encrypted certs that runs like a CDN.