Skip to content

Instantly share code, notes, and snippets.

@FiloSottile
Created December 22, 2015 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FiloSottile/2235cbfff2c6a5979934 to your computer and use it in GitHub Desktop.
Save FiloSottile/2235cbfff2c6a5979934 to your computer and use it in GitHub Desktop.
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"image/color"
"testing"
"github.com/gonum/plot"
"github.com/gonum/plot/plotter"
"github.com/gonum/plot/vg"
"github.com/gonum/plot/vg/draw"
)
func TestHMACSumTiming(t *testing.T) {
sumData := make(plotter.XYs, 70-45)
constData := make(plotter.XYs, 70-45)
data := []byte("01234567890123456789012345678901234567890123456789012345678901234567890123456789")
sumBuf := make([]byte, 0, 100)
for n := 45; n < 70; n++ {
var res1, res2 []byte
ns := testing.Benchmark(func(b *testing.B) {
h := hmac.New(newConstantTimeHash(sha1.New), make([]byte, 30))
h.Write(data[:n])
b.ResetTimer()
for i := 0; i < b.N; i++ {
res1 = h.Sum(sumBuf)
}
}).NsPerOp()
t.Logf("ConstantTimeSum %d bytes: %d ns/op", n, ns)
constData[n-45].X = float64(n)
constData[n-45].Y = float64(ns)
ns = testing.Benchmark(func(b *testing.B) {
h := hmac.New(sha1.New, make([]byte, 30))
h.Write(data[:n])
b.ResetTimer()
for i := 0; i < b.N; i++ {
res2 = h.Sum(sumBuf)
}
}).NsPerOp()
t.Logf("Sum %d bytes: %d ns/op", n, ns)
sumData[n-45].X = float64(n)
sumData[n-45].Y = float64(ns)
if !bytes.Equal(res1, res2) {
t.Errorf("different output at length %d", n)
}
}
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "Sum() timings"
p.X.Label.Text = "Buffer bytes"
p.Y.Label.Text = "ns"
s, err := plotter.NewScatter(sumData)
if err != nil {
panic(err)
}
c, err := plotter.NewScatter(constData)
if err != nil {
panic(err)
}
c.GlyphStyle.Shape = draw.PyramidGlyph{}
c.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
p.Add(s, c)
if err := p.Save(7*vg.Inch, 5*vg.Inch, "sum.png"); err != nil {
panic(err)
}
}
func TestHMACTotalTiming(t *testing.T) {
sumData := make(plotter.XYs, 256)
constData := make(plotter.XYs, 256)
naiveData := make(plotter.XYs, 256)
data := []byte("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
sumBuf := make([]byte, 0, 100)
for n := 0; n < 256; n++ {
var res1, res2 []byte
ns := testing.Benchmark(func(b *testing.B) {
h := hmac.New(newConstantTimeHash(sha1.New), make([]byte, 30))
for i := 0; i < b.N; i++ {
h.Reset()
h.Write(data[:len(data)-n])
res1 = h.Sum(sumBuf)
h.Write(data[len(data)-n:])
}
}).NsPerOp()
t.Logf("ConstantTimeHash %d bytes: %d ns/op", n, ns)
constData[n].X = float64(len(data) - n)
constData[n].Y = float64(ns)
ns = testing.Benchmark(func(b *testing.B) {
h := hmac.New(sha1.New, make([]byte, 30))
for i := 0; i < b.N; i++ {
h.Reset()
h.Write(data[:len(data)-n])
res2 = h.Sum(sumBuf)
}
}).NsPerOp()
t.Logf("Sum %d bytes: %d ns/op", n, ns)
sumData[n].X = float64(len(data) - n)
sumData[n].Y = float64(ns)
ns = testing.Benchmark(func(b *testing.B) {
h := hmac.New(sha1.New, make([]byte, 30))
for i := 0; i < b.N; i++ {
h.Reset()
h.Write(data[:len(data)-n])
res2 = h.Sum(sumBuf)
h.Write(data[len(data)-n:])
}
}).NsPerOp()
t.Logf("Sum+Write %d bytes: %d ns/op", n, ns)
naiveData[n].X = float64(len(data) - n)
naiveData[n].Y = float64(ns)
if !bytes.Equal(res1, res2) {
t.Errorf("different output at length %d", n)
}
}
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "HMAC timings"
p.X.Label.Text = "First Write() bytes"
p.Y.Label.Text = "ns"
s, err := plotter.NewScatter(sumData)
if err != nil {
panic(err)
}
c, err := plotter.NewScatter(constData)
if err != nil {
panic(err)
}
c.GlyphStyle.Shape = draw.PyramidGlyph{}
c.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
x, err := plotter.NewScatter(naiveData)
if err != nil {
panic(err)
}
x.GlyphStyle.Shape = draw.CrossGlyph{}
x.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
p.Add(s, c, x)
if err := p.Save(297*vg.Millimeter, 210*vg.Millimeter, "hmac.png"); err != nil {
panic(err)
}
}
func TestDecryptTiming(t *testing.T) {
newData := make(plotter.XYs, 256)
// oldData := make(plotter.XYs, 256)
data := []byte("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
key := []byte("YELLOW SUBMARINE")
for n := 0; n < 256; n++ {
data[len(data)-1] = byte(n)
ns := testing.Benchmark(func(b *testing.B) {
hc := &halfConn{
version: VersionTLS10,
cipher: cipherAES(key, key, true),
mac: macSHA1(VersionTLS10, key),
}
enc := make([]byte, len(data))
cipherAES(key, key, false).(cbcMode).CryptBlocks(enc, data)
bl := &block{data: make([]byte, len(enc)+recordHeaderLen)}
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy(bl.data[recordHeaderLen:], enc)
hc.decrypt(bl)
}
}).NsPerOp()
t.Logf("[NEW] Padding value %d: %d ns/op", n, ns)
newData[n].X = float64(n)
newData[n].Y = float64(ns)
// ns = testing.Benchmark(func(b *testing.B) {
// hc := &halfConn{
// version: VersionTLS10,
// cipher: cipherAES(key, key, true),
// mac: tls10MAC{hmac.New(sha1.New, key)},
// }
// enc := make([]byte, len(data))
// cipherAES(key, key, false).(cbcMode).CryptBlocks(enc, data)
// bl := &block{data: make([]byte, len(enc)+recordHeaderLen)}
// b.ResetTimer()
// for i := 0; i < b.N; i++ {
// copy(bl.data[recordHeaderLen:], enc)
// hc.decryptOld(bl)
// }
// }).NsPerOp()
// t.Logf("[OLD] Padding value %d: %d ns/op", n, ns)
// oldData[n].X = float64(n)
// oldData[n].Y = float64(ns)
}
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "decrypt() timings"
p.X.Label.Text = "Padding value"
p.Y.Label.Text = "ns"
n, err := plotter.NewScatter(newData)
if err != nil {
panic(err)
}
n.GlyphStyle.Shape = draw.CrossGlyph{}
n.GlyphStyle.Color = color.RGBA{R: 255, A: 255}
// o, err := plotter.NewScatter(oldData)
// if err != nil {
// panic(err)
// }
p.Add(n)
if err := p.Save(297*vg.Millimeter, 210*vg.Millimeter, "decrypt.png"); err != nil {
panic(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment