Initial import
This commit is contained in:
parent
1e238cbbe0
commit
c8011ea44b
26
README.md
26
README.md
|
@ -1,2 +1,26 @@
|
|||
# cryptodev
|
||||
Implementation in go of AES-CBC using cryptodev
|
||||
Implementation in go of AES-CBC using cryptodev.
|
||||
|
||||
Installation and Usage
|
||||
----------------------
|
||||
This package can be installed with the go get command:
|
||||
|
||||
$ go get github.com/stacktic/cryptodev
|
||||
|
||||
To use this package, you only need to replace crypto/aes with github.com/stacktic/cryptodev/aes in your import.
|
||||
|
||||
Performance
|
||||
-----------
|
||||
AES-CBC from Go source:
|
||||
|
||||
$ go test -bench CBC crypto/cipher
|
||||
BenchmarkAESCBCEncrypt1K-2 20000 66981 ns/op 15.29 MB/s
|
||||
BenchmarkAESCBCDecrypt1K-2 20000 65053 ns/op 15.74 MB/s
|
||||
PASS
|
||||
ok crypto/cipher 3.993s
|
||||
|
||||
AES-CBC with cryptodev:
|
||||
|
||||
$ go test -bench CBC github.com/stacktic/cryptodev/cipher
|
||||
BenchmarkAESCBCEncrypt1K-2 100000 20015 ns/op 51.16 MB/s
|
||||
BenchmarkAESCBCDecrypt1K-2 100000 19832 ns/op 51.63 MB/s
|
||||
|
|
144
aes/aes.go
Normal file
144
aes/aes.go
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
** Copyright (c) 2017 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package aes
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
|
||||
"github.com/stacktic/cryptodev/cryptodev"
|
||||
)
|
||||
|
||||
const BlockSize = 16
|
||||
|
||||
type cryptodevAES struct {
|
||||
key []byte
|
||||
b cipher.Block
|
||||
}
|
||||
|
||||
type cryptodevAESCBCEncrypter struct {
|
||||
cryptodevAES
|
||||
s *cryptodev.Session
|
||||
iv []byte
|
||||
}
|
||||
|
||||
type cryptodevAESCBCDecrypter struct {
|
||||
cryptodevAES
|
||||
s *cryptodev.Session
|
||||
iv []byte
|
||||
tmp []byte
|
||||
}
|
||||
|
||||
func (c *cryptodevAES) NewCBCDecrypter(iv []byte) cipher.BlockMode {
|
||||
var err error
|
||||
var s *cryptodev.Session
|
||||
|
||||
if len(iv) != c.BlockSize() {
|
||||
panic("cipher.NewCBCDecrypter: IV length must equal block size")
|
||||
}
|
||||
|
||||
if s, err = cryptodev.NewSession(cryptodev.CRYPTO_AES_CBC, c.key); err != nil {
|
||||
return cipher.NewCBCDecrypter(c.b, iv)
|
||||
}
|
||||
|
||||
bm := &cryptodevAESCBCDecrypter{
|
||||
cryptodevAES: *c,
|
||||
s: s,
|
||||
iv: make([]byte, BlockSize),
|
||||
tmp: make([]byte, BlockSize),
|
||||
}
|
||||
copy(bm.iv, iv)
|
||||
return bm
|
||||
}
|
||||
|
||||
func (c *cryptodevAES) NewCBCEncrypter(iv []byte) cipher.BlockMode {
|
||||
var err error
|
||||
var s *cryptodev.Session
|
||||
|
||||
if len(iv) != c.BlockSize() {
|
||||
panic("cipher.NewCBCEncrypter: IV length must equal block size")
|
||||
}
|
||||
|
||||
if s, err = cryptodev.NewSession(cryptodev.CRYPTO_AES_CBC, c.key); err != nil {
|
||||
return cipher.NewCBCEncrypter(c.b, iv)
|
||||
}
|
||||
bm := &cryptodevAESCBCEncrypter{
|
||||
cryptodevAES: *c,
|
||||
s: s,
|
||||
iv: make([]byte, BlockSize),
|
||||
}
|
||||
copy(bm.iv[:], iv)
|
||||
return bm
|
||||
}
|
||||
|
||||
func NewCipher(key []byte) (cipher.Block, error) {
|
||||
var err error
|
||||
var b cipher.Block
|
||||
|
||||
if b, err = aes.NewCipher(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cryptodevAES{key: key, b: b}, nil
|
||||
}
|
||||
|
||||
func (c *cryptodevAES) Encrypt(src []byte, dst []byte) {
|
||||
c.b.Encrypt(src, dst)
|
||||
}
|
||||
|
||||
func (c *cryptodevAES) Decrypt(src []byte, dst []byte) {
|
||||
c.b.Decrypt(src, dst)
|
||||
}
|
||||
|
||||
func (c *cryptodevAES) BlockSize() int {
|
||||
return BlockSize
|
||||
}
|
||||
|
||||
func (c *cryptodevAESCBCDecrypter) CryptBlocks(dst, src []byte) {
|
||||
if len(src)%BlockSize != 0 {
|
||||
panic("crypto/cipher: input not full blocks")
|
||||
}
|
||||
if len(dst) < len(src) {
|
||||
panic("crypto/cipher: output smaller than input")
|
||||
}
|
||||
if len(src) > 0 {
|
||||
copy(c.tmp, src[len(src)-BlockSize:])
|
||||
c.s.Decrypt(dst, src, c.iv)
|
||||
c.tmp, c.iv = c.iv, c.tmp
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cryptodevAESCBCEncrypter) CryptBlocks(dst, src []byte) {
|
||||
if len(src)%BlockSize != 0 {
|
||||
panic("crypto/cipher: input not full blocks")
|
||||
}
|
||||
if len(dst) < len(src) {
|
||||
panic("crypto/cipher: output smaller than input")
|
||||
}
|
||||
if len(src) > 0 {
|
||||
c.s.Encrypt(dst, src, c.iv)
|
||||
copy(c.iv, dst[len(dst)-BlockSize:])
|
||||
}
|
||||
}
|
216
aes/aes_test.go
Normal file
216
aes/aes_test.go
Normal file
|
@ -0,0 +1,216 @@
|
|||
// Copyright 2009 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 aes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test vectors are from FIPS 197:
|
||||
// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||
|
||||
// Appendix A of FIPS 197: Key expansion examples
|
||||
type KeyTest struct {
|
||||
key []byte
|
||||
enc []uint32
|
||||
dec []uint32 // decryption expansion; not in FIPS 197, computed from C implementation.
|
||||
}
|
||||
|
||||
var keyTests = []KeyTest{
|
||||
{
|
||||
// A.1. Expansion of a 128-bit Cipher Key
|
||||
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
|
||||
[]uint32{
|
||||
0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c,
|
||||
0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605,
|
||||
0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f,
|
||||
0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b,
|
||||
0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00,
|
||||
0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc,
|
||||
0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd,
|
||||
0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f,
|
||||
0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f,
|
||||
0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e,
|
||||
0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
|
||||
},
|
||||
[]uint32{
|
||||
0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
|
||||
0xc7b5a63, 0x1319eafe, 0xb0398890, 0x664cfbb4,
|
||||
0xdf7d925a, 0x1f62b09d, 0xa320626e, 0xd6757324,
|
||||
0x12c07647, 0xc01f22c7, 0xbc42d2f3, 0x7555114a,
|
||||
0x6efcd876, 0xd2df5480, 0x7c5df034, 0xc917c3b9,
|
||||
0x6ea30afc, 0xbc238cf6, 0xae82a4b4, 0xb54a338d,
|
||||
0x90884413, 0xd280860a, 0x12a12842, 0x1bc89739,
|
||||
0x7c1f13f7, 0x4208c219, 0xc021ae48, 0x969bf7b,
|
||||
0xcc7505eb, 0x3e17d1ee, 0x82296c51, 0xc9481133,
|
||||
0x2b3708a7, 0xf262d405, 0xbc3ebdbf, 0x4b617d62,
|
||||
0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x9cf4f3c,
|
||||
},
|
||||
},
|
||||
{
|
||||
// A.2. Expansion of a 192-bit Cipher Key
|
||||
[]byte{
|
||||
0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
|
||||
0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
|
||||
},
|
||||
[]uint32{
|
||||
0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5,
|
||||
0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5,
|
||||
0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2,
|
||||
0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd,
|
||||
0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f,
|
||||
0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6,
|
||||
0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767,
|
||||
0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971,
|
||||
0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3,
|
||||
0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e,
|
||||
0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753,
|
||||
0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5,
|
||||
0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
// A.3. Expansion of a 256-bit Cipher Key
|
||||
[]byte{
|
||||
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
|
||||
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
|
||||
},
|
||||
[]uint32{
|
||||
0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781,
|
||||
0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4,
|
||||
0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde,
|
||||
0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a,
|
||||
0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96,
|
||||
0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3,
|
||||
0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464,
|
||||
0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214,
|
||||
0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80,
|
||||
0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239,
|
||||
0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15,
|
||||
0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3,
|
||||
0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a,
|
||||
0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d,
|
||||
0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
// Appendix B, C of FIPS 197: Cipher examples, Example vectors.
|
||||
type CryptTest struct {
|
||||
key []byte
|
||||
in []byte
|
||||
out []byte
|
||||
}
|
||||
|
||||
var encryptTests = []CryptTest{
|
||||
{
|
||||
// Appendix B.
|
||||
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
|
||||
[]byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
|
||||
[]byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
|
||||
},
|
||||
{
|
||||
// Appendix C.1. AES-128
|
||||
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
|
||||
[]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
|
||||
[]byte{0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a},
|
||||
},
|
||||
{
|
||||
// Appendix C.2. AES-192
|
||||
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
},
|
||||
[]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
|
||||
[]byte{0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91},
|
||||
},
|
||||
{
|
||||
// Appendix C.3. AES-256
|
||||
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
},
|
||||
[]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
|
||||
[]byte{0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89},
|
||||
},
|
||||
}
|
||||
|
||||
// Test Cipher Encrypt method against FIPS 197 examples.
|
||||
func TestCipherEncrypt(t *testing.T) {
|
||||
for i, tt := range encryptTests {
|
||||
c, err := NewCipher(tt.key)
|
||||
if err != nil {
|
||||
t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
|
||||
continue
|
||||
}
|
||||
out := make([]byte, len(tt.in))
|
||||
c.Encrypt(out, tt.in)
|
||||
for j, v := range out {
|
||||
if v != tt.out[j] {
|
||||
t.Errorf("Cipher.Encrypt %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test Cipher Decrypt against FIPS 197 examples.
|
||||
func TestCipherDecrypt(t *testing.T) {
|
||||
for i, tt := range encryptTests {
|
||||
c, err := NewCipher(tt.key)
|
||||
if err != nil {
|
||||
t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
|
||||
continue
|
||||
}
|
||||
plain := make([]byte, len(tt.in))
|
||||
c.Decrypt(plain, tt.out)
|
||||
for j, v := range plain {
|
||||
if v != tt.in[j] {
|
||||
t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mustPanic(t *testing.T, msg string, f func()) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
t.Errorf("function did not panic, wanted %q", msg)
|
||||
} else if err != msg {
|
||||
t.Errorf("got panic %v, wanted %q", err, msg)
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
func BenchmarkEncrypt(b *testing.B) {
|
||||
tt := encryptTests[0]
|
||||
c, err := NewCipher(tt.key)
|
||||
if err != nil {
|
||||
b.Fatal("NewCipher:", err)
|
||||
}
|
||||
out := make([]byte, len(tt.in))
|
||||
b.SetBytes(int64(len(out)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Encrypt(out, tt.in)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecrypt(b *testing.B) {
|
||||
tt := encryptTests[0]
|
||||
c, err := NewCipher(tt.key)
|
||||
if err != nil {
|
||||
b.Fatal("NewCipher:", err)
|
||||
}
|
||||
out := make([]byte, len(tt.out))
|
||||
b.SetBytes(int64(len(out)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Decrypt(out, tt.out)
|
||||
}
|
||||
}
|
156
cipher/benchmark_test.go
Normal file
156
cipher/benchmark_test.go
Normal file
|
@ -0,0 +1,156 @@
|
|||
// Copyright 2013 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 cipher_test
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"testing"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
func benchmarkAESGCMSeal(b *testing.B, buf []byte) {
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var nonce [12]byte
|
||||
var ad [13]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
aesgcm, _ := cipher.NewGCM(aes)
|
||||
var out []byte
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
out = aesgcm.Seal(out[:0], nonce[:], buf, ad[:])
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkAESGCMOpen(b *testing.B, buf []byte) {
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var nonce [12]byte
|
||||
var ad [13]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
aesgcm, _ := cipher.NewGCM(aes)
|
||||
var out []byte
|
||||
out = aesgcm.Seal(out[:0], nonce[:], buf, ad[:])
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := aesgcm.Open(buf[:0], nonce[:], out, ad[:])
|
||||
if err != nil {
|
||||
b.Errorf("Open: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAESGCMSeal1K(b *testing.B) {
|
||||
benchmarkAESGCMSeal(b, make([]byte, 1024))
|
||||
}
|
||||
|
||||
func BenchmarkAESGCMOpen1K(b *testing.B) {
|
||||
benchmarkAESGCMOpen(b, make([]byte, 1024))
|
||||
}
|
||||
|
||||
func BenchmarkAESGCMSeal8K(b *testing.B) {
|
||||
benchmarkAESGCMSeal(b, make([]byte, 8*1024))
|
||||
}
|
||||
|
||||
func BenchmarkAESGCMOpen8K(b *testing.B) {
|
||||
benchmarkAESGCMOpen(b, make([]byte, 8*1024))
|
||||
}
|
||||
|
||||
// If we test exactly 1K blocks, we would generate exact multiples of
|
||||
// the cipher's block size, and the cipher stream fragments would
|
||||
// always be wordsize aligned, whereas non-aligned is a more typical
|
||||
// use-case.
|
||||
const almost1K = 1024 - 5
|
||||
|
||||
func BenchmarkAESCFBEncrypt1K(b *testing.B) {
|
||||
buf := make([]byte, almost1K)
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
ctr := cipher.NewCFBEncrypter(aes, iv[:])
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ctr.XORKeyStream(buf, buf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAESCFBDecrypt1K(b *testing.B) {
|
||||
buf := make([]byte, almost1K)
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
ctr := cipher.NewCFBDecrypter(aes, iv[:])
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ctr.XORKeyStream(buf, buf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAESOFB1K(b *testing.B) {
|
||||
buf := make([]byte, almost1K)
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
ctr := cipher.NewOFB(aes, iv[:])
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ctr.XORKeyStream(buf, buf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAESCTR1K(b *testing.B) {
|
||||
buf := make([]byte, almost1K)
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
ctr := cipher.NewCTR(aes, iv[:])
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ctr.XORKeyStream(buf, buf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAESCBCEncrypt1K(b *testing.B) {
|
||||
buf := make([]byte, 1024)
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
cbc := cipher.NewCBCEncrypter(aes, iv[:])
|
||||
for i := 0; i < b.N; i++ {
|
||||
cbc.CryptBlocks(buf, buf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAESCBCDecrypt1K(b *testing.B) {
|
||||
buf := make([]byte, 1024)
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
cbc := cipher.NewCBCDecrypter(aes, iv[:])
|
||||
for i := 0; i < b.N; i++ {
|
||||
cbc.CryptBlocks(buf, buf)
|
||||
}
|
||||
}
|
147
cipher/cbc_aes_test.go
Normal file
147
cipher/cbc_aes_test.go
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2009 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.
|
||||
|
||||
// CBC AES test vectors.
|
||||
|
||||
// See U.S. National Institute of Standards and Technology (NIST)
|
||||
// Special Publication 800-38A, ``Recommendation for Block Cipher
|
||||
// Modes of Operation,'' 2001 Edition, pp. 24-29.
|
||||
|
||||
package cipher_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"testing"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
var cbcAESTests = []struct {
|
||||
name string
|
||||
key []byte
|
||||
iv []byte
|
||||
in []byte
|
||||
out []byte
|
||||
}{
|
||||
// NIST SP 800-38A pp 27-29
|
||||
{
|
||||
"CBC-AES128",
|
||||
commonKey128,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
|
||||
0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
|
||||
0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
|
||||
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CBC-AES192",
|
||||
commonKey192,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
|
||||
0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
|
||||
0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
|
||||
0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CBC-AES256",
|
||||
commonKey256,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
|
||||
0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
|
||||
0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
|
||||
0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestCBCEncrypterAES(t *testing.T) {
|
||||
for _, test := range cbcAESTests {
|
||||
c, err := aes.NewCipher(test.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
encrypter := cipher.NewCBCEncrypter(c, test.iv)
|
||||
|
||||
data := make([]byte, len(test.in))
|
||||
copy(data, test.in)
|
||||
|
||||
encrypter.CryptBlocks(data, data)
|
||||
if !bytes.Equal(test.out, data) {
|
||||
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
|
||||
}
|
||||
}
|
||||
for _, test := range cbcAESTests {
|
||||
c, err := aes.NewCipher(test.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
encrypter := cipher.NewCBCEncrypter(c, test.iv)
|
||||
|
||||
data := make([]byte, len(test.in))
|
||||
copy(data, test.in)
|
||||
|
||||
for i := 0; i < len(test.out); i += encrypter.BlockSize() {
|
||||
encrypter.CryptBlocks(data[i:i+encrypter.BlockSize()], data[i:i+encrypter.BlockSize()])
|
||||
}
|
||||
|
||||
if !bytes.Equal(test.out, data) {
|
||||
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCBCDecrypterAES(t *testing.T) {
|
||||
for _, test := range cbcAESTests {
|
||||
c, err := aes.NewCipher(test.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
decrypter := cipher.NewCBCDecrypter(c, test.iv)
|
||||
|
||||
data := make([]byte, len(test.out))
|
||||
copy(data, test.out)
|
||||
|
||||
decrypter.CryptBlocks(data, data)
|
||||
if !bytes.Equal(test.in, data) {
|
||||
t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test.name, data, test.in)
|
||||
}
|
||||
}
|
||||
for _, test := range cbcAESTests {
|
||||
c, err := aes.NewCipher(test.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
decrypter := cipher.NewCBCDecrypter(c, test.iv)
|
||||
|
||||
data := make([]byte, len(test.in))
|
||||
copy(data, test.out)
|
||||
|
||||
for i := 0; i < len(test.out); i += decrypter.BlockSize() {
|
||||
decrypter.CryptBlocks(data[i:i+decrypter.BlockSize()], data[i:i+decrypter.BlockSize()])
|
||||
}
|
||||
|
||||
if !bytes.Equal(test.in, data) {
|
||||
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
114
cipher/cfb_test.go
Normal file
114
cipher/cfb_test.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
// 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 cipher_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
// cfbTests contains the test vectors from
|
||||
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section
|
||||
// F.3.13.
|
||||
var cfbTests = []struct {
|
||||
key, iv, plaintext, ciphertext string
|
||||
}{
|
||||
{
|
||||
"2b7e151628aed2a6abf7158809cf4f3c",
|
||||
"000102030405060708090a0b0c0d0e0f",
|
||||
"6bc1bee22e409f96e93d7e117393172a",
|
||||
"3b3fd92eb72dad20333449f8e83cfb4a",
|
||||
},
|
||||
{
|
||||
"2b7e151628aed2a6abf7158809cf4f3c",
|
||||
"3B3FD92EB72DAD20333449F8E83CFB4A",
|
||||
"ae2d8a571e03ac9c9eb76fac45af8e51",
|
||||
"c8a64537a0b3a93fcde3cdad9f1ce58b",
|
||||
},
|
||||
{
|
||||
"2b7e151628aed2a6abf7158809cf4f3c",
|
||||
"C8A64537A0B3A93FCDE3CDAD9F1CE58B",
|
||||
"30c81c46a35ce411e5fbc1191a0a52ef",
|
||||
"26751f67a3cbb140b1808cf187a4f4df",
|
||||
},
|
||||
{
|
||||
"2b7e151628aed2a6abf7158809cf4f3c",
|
||||
"26751F67A3CBB140B1808CF187A4F4DF",
|
||||
"f69f2445df4f9b17ad2b417be66c3710",
|
||||
"c04b05357c5d1c0eeac4c66f9ff7f2e6",
|
||||
},
|
||||
}
|
||||
|
||||
func TestCFBVectors(t *testing.T) {
|
||||
for i, test := range cfbTests {
|
||||
key, err := hex.DecodeString(test.key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
iv, err := hex.DecodeString(test.iv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plaintext, err := hex.DecodeString(test.plaintext)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected, err := hex.DecodeString(test.ciphertext)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
cfb := cipher.NewCFBEncrypter(block, iv)
|
||||
cfb.XORKeyStream(ciphertext, plaintext)
|
||||
|
||||
if !bytes.Equal(ciphertext, expected) {
|
||||
t.Errorf("#%d: wrong output: got %x, expected %x", i, ciphertext, expected)
|
||||
}
|
||||
|
||||
cfbdec := cipher.NewCFBDecrypter(block, iv)
|
||||
plaintextCopy := make([]byte, len(ciphertext))
|
||||
cfbdec.XORKeyStream(plaintextCopy, ciphertext)
|
||||
|
||||
if !bytes.Equal(plaintextCopy, plaintextCopy) {
|
||||
t.Errorf("#%d: wrong plaintext: got %x, expected %x", i, plaintextCopy, plaintext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCFBInverse(t *testing.T) {
|
||||
block, err := aes.NewCipher(commonKey128)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
plaintext := []byte("this is the plaintext. this is the plaintext.")
|
||||
iv := make([]byte, block.BlockSize())
|
||||
rand.Reader.Read(iv)
|
||||
cfb := cipher.NewCFBEncrypter(block, iv)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
copy(ciphertext, plaintext)
|
||||
cfb.XORKeyStream(ciphertext, ciphertext)
|
||||
|
||||
cfbdec := cipher.NewCFBDecrypter(block, iv)
|
||||
plaintextCopy := make([]byte, len(plaintext))
|
||||
copy(plaintextCopy, ciphertext)
|
||||
cfbdec.XORKeyStream(plaintextCopy, plaintextCopy)
|
||||
|
||||
if !bytes.Equal(plaintextCopy, plaintext) {
|
||||
t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
|
||||
}
|
||||
}
|
91
cipher/cipher_test.go
Normal file
91
cipher/cipher_test.go
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2013 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 cipher_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"testing"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
func TestCryptBlocks(t *testing.T) {
|
||||
buf := make([]byte, 16)
|
||||
block, _ := aes.NewCipher(buf)
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, buf)
|
||||
mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
|
||||
mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
|
||||
|
||||
mode = cipher.NewCBCEncrypter(block, buf)
|
||||
mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
|
||||
mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
|
||||
}
|
||||
|
||||
func mustPanic(t *testing.T, msg string, f func()) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
t.Errorf("function did not panic, wanted %q", msg)
|
||||
} else if err != msg {
|
||||
t.Errorf("got panic %v, wanted %q", err, msg)
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
func TestEmptyPlaintext(t *testing.T) {
|
||||
var key [16]byte
|
||||
a, err := aes.NewCipher(key[:16])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d, err := des.NewCipher(key[:8])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := 16
|
||||
pt := make([]byte, s)
|
||||
ct := make([]byte, s)
|
||||
for i := 0; i < 16; i++ {
|
||||
pt[i], ct[i] = byte(i), byte(i)
|
||||
}
|
||||
|
||||
assertEqual := func(name string, got, want []byte) {
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Fatalf("%s: got %v, want %v", name, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
for _, b := range []cipher.Block{a, d} {
|
||||
iv := make([]byte, b.BlockSize())
|
||||
cbce := cipher.NewCBCEncrypter(b, iv)
|
||||
cbce.CryptBlocks(ct, pt[:0])
|
||||
assertEqual("CBC encrypt", ct, pt)
|
||||
|
||||
cbcd := cipher.NewCBCDecrypter(b, iv)
|
||||
cbcd.CryptBlocks(ct, pt[:0])
|
||||
assertEqual("CBC decrypt", ct, pt)
|
||||
|
||||
cfbe := cipher.NewCFBEncrypter(b, iv)
|
||||
cfbe.XORKeyStream(ct, pt[:0])
|
||||
assertEqual("CFB encrypt", ct, pt)
|
||||
|
||||
cfbd := cipher.NewCFBDecrypter(b, iv)
|
||||
cfbd.XORKeyStream(ct, pt[:0])
|
||||
assertEqual("CFB decrypt", ct, pt)
|
||||
|
||||
ctr := cipher.NewCTR(b, iv)
|
||||
ctr.XORKeyStream(ct, pt[:0])
|
||||
assertEqual("CTR", ct, pt)
|
||||
|
||||
ofb := cipher.NewOFB(b, iv)
|
||||
ofb.XORKeyStream(ct, pt[:0])
|
||||
assertEqual("OFB", ct, pt)
|
||||
}
|
||||
}
|
28
cipher/common_test.go
Normal file
28
cipher/common_test.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2009 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 cipher_test
|
||||
|
||||
// Common values for tests.
|
||||
|
||||
var commonInput = []byte{
|
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
|
||||
}
|
||||
|
||||
var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
|
||||
|
||||
var commonKey192 = []byte{
|
||||
0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
|
||||
0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
|
||||
}
|
||||
|
||||
var commonKey256 = []byte{
|
||||
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
|
||||
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
|
||||
}
|
||||
|
||||
var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
|
103
cipher/ctr_aes_test.go
Normal file
103
cipher/ctr_aes_test.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2009 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.
|
||||
|
||||
// CTR AES test vectors.
|
||||
|
||||
// See U.S. National Institute of Standards and Technology (NIST)
|
||||
// Special Publication 800-38A, ``Recommendation for Block Cipher
|
||||
// Modes of Operation,'' 2001 Edition, pp. 55-58.
|
||||
|
||||
package cipher_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"testing"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
|
||||
|
||||
var ctrAESTests = []struct {
|
||||
name string
|
||||
key []byte
|
||||
iv []byte
|
||||
in []byte
|
||||
out []byte
|
||||
}{
|
||||
// NIST SP 800-38A pp 55-58
|
||||
{
|
||||
"CTR-AES128",
|
||||
commonKey128,
|
||||
commonCounter,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
|
||||
0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
|
||||
0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
|
||||
0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CTR-AES192",
|
||||
commonKey192,
|
||||
commonCounter,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
|
||||
0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
|
||||
0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
|
||||
0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CTR-AES256",
|
||||
commonKey256,
|
||||
commonCounter,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
|
||||
0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
|
||||
0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
|
||||
0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestCTR_AES(t *testing.T) {
|
||||
for _, tt := range ctrAESTests {
|
||||
test := tt.name
|
||||
|
||||
c, err := aes.NewCipher(tt.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 0; j <= 5; j += 5 {
|
||||
in := tt.in[0 : len(tt.in)-j]
|
||||
ctr := cipher.NewCTR(c, tt.iv)
|
||||
encrypted := make([]byte, len(in))
|
||||
ctr.XORKeyStream(encrypted, in)
|
||||
if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
|
||||
t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
|
||||
}
|
||||
}
|
||||
|
||||
for j := 0; j <= 7; j += 7 {
|
||||
in := tt.out[0 : len(tt.out)-j]
|
||||
ctr := cipher.NewCTR(c, tt.iv)
|
||||
plain := make([]byte, len(in))
|
||||
ctr.XORKeyStream(plain, in)
|
||||
if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
|
||||
t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
55
cipher/ctr_test.go
Normal file
55
cipher/ctr_test.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2015 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 cipher_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type noopBlock int
|
||||
|
||||
func (b noopBlock) BlockSize() int { return int(b) }
|
||||
func (noopBlock) Encrypt(dst, src []byte) { copy(dst, src) }
|
||||
func (noopBlock) Decrypt(dst, src []byte) { copy(dst, src) }
|
||||
|
||||
func inc(b []byte) {
|
||||
for i := len(b) - 1; i >= 0; i++ {
|
||||
b[i]++
|
||||
if b[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func xor(a, b []byte) {
|
||||
for i := range a {
|
||||
a[i] ^= b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func TestCTR(t *testing.T) {
|
||||
for size := 64; size <= 1024; size *= 2 {
|
||||
iv := make([]byte, size)
|
||||
ctr := cipher.NewCTR(noopBlock(size), iv)
|
||||
src := make([]byte, 1024)
|
||||
for i := range src {
|
||||
src[i] = 0xff
|
||||
}
|
||||
want := make([]byte, 1024)
|
||||
copy(want, src)
|
||||
counter := make([]byte, size)
|
||||
for i := 1; i < len(want)/size; i++ {
|
||||
inc(counter)
|
||||
xor(want[i*size:(i+1)*size], counter)
|
||||
}
|
||||
dst := make([]byte, 1024)
|
||||
ctr.XORKeyStream(dst, src)
|
||||
if !bytes.Equal(dst, want) {
|
||||
t.Errorf("for size %d\nhave %x\nwant %x", size, dst, want)
|
||||
}
|
||||
}
|
||||
}
|
337
cipher/example_test.go
Normal file
337
cipher/example_test.go
Normal file
|
@ -0,0 +1,337 @@
|
|||
// Copyright 2012 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 cipher_test
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
func ExampleNewGCM_encrypt() {
|
||||
// The key argument should be the AES key, either 16 or 32 bytes
|
||||
// to select AES-128 or AES-256.
|
||||
key := []byte("AES256Key-32Characters1234567890")
|
||||
plaintext := []byte("exampleplaintext")
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
|
||||
fmt.Printf("%x\n", ciphertext)
|
||||
}
|
||||
|
||||
func ExampleNewGCM_decrypt() {
|
||||
// The key argument should be the AES key, either 16 or 32 bytes
|
||||
// to select AES-128 or AES-256.
|
||||
key := []byte("AES256Key-32Characters1234567890")
|
||||
ciphertext, _ := hex.DecodeString("1019aa66cd7c024f9efd0038899dae1973ee69427f5a6579eba292ffe1b5a260")
|
||||
|
||||
nonce, _ := hex.DecodeString("37b8e8a308c354048d245f6d")
|
||||
|
||||
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 ExampleNewCBCDecrypter() {
|
||||
key := []byte("example key 1234")
|
||||
ciphertext, _ := hex.DecodeString("f363f3ccdcb12bb883abf484ba77d9cd7d32b5baecb3d4b1b3e0e4beffdb3ded")
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
panic("ciphertext too short")
|
||||
}
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
|
||||
// CBC mode always works in whole blocks.
|
||||
if len(ciphertext)%aes.BlockSize != 0 {
|
||||
panic("ciphertext is not a multiple of the block size")
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
|
||||
// CryptBlocks can work in-place if the two arguments are the same.
|
||||
mode.CryptBlocks(ciphertext, ciphertext)
|
||||
|
||||
// If the original plaintext lengths are not a multiple of the block
|
||||
// size, padding would have to be added when encrypting, which would be
|
||||
// removed at this point. For an example, see
|
||||
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's
|
||||
// critical to note that ciphertexts must be authenticated (i.e. by
|
||||
// using crypto/hmac) before being decrypted in order to avoid creating
|
||||
// a padding oracle.
|
||||
|
||||
fmt.Printf("%s\n", ciphertext)
|
||||
// Output: exampleplaintext
|
||||
}
|
||||
|
||||
func ExampleNewCBCEncrypter() {
|
||||
key := []byte("example key 1234")
|
||||
plaintext := []byte("exampleplaintext")
|
||||
|
||||
// CBC mode works on blocks so plaintexts may need to be padded to the
|
||||
// next whole block. For an example of such padding, see
|
||||
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
|
||||
// assume that the plaintext is already of the correct length.
|
||||
if len(plaintext)%aes.BlockSize != 0 {
|
||||
panic("plaintext is not a multiple of the block size")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
// It's important to remember that ciphertexts must be authenticated
|
||||
// (i.e. by using crypto/hmac) as well as being encrypted in order to
|
||||
// be secure.
|
||||
|
||||
fmt.Printf("%x\n", ciphertext)
|
||||
}
|
||||
|
||||
func ExampleNewCFBDecrypter() {
|
||||
key := []byte("example key 1234")
|
||||
ciphertext, _ := hex.DecodeString("22277966616d9bc47177bd02603d08c9a67d5380d0fe8cf3b44438dff7b9")
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
panic("ciphertext too short")
|
||||
}
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
|
||||
// XORKeyStream can work in-place if the two arguments are the same.
|
||||
stream.XORKeyStream(ciphertext, ciphertext)
|
||||
fmt.Printf("%s", ciphertext)
|
||||
// Output: some plaintext
|
||||
}
|
||||
|
||||
func ExampleNewCFBEncrypter() {
|
||||
key := []byte("example key 1234")
|
||||
plaintext := []byte("some plaintext")
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
// It's important to remember that ciphertexts must be authenticated
|
||||
// (i.e. by using crypto/hmac) as well as being encrypted in order to
|
||||
// be secure.
|
||||
}
|
||||
|
||||
func ExampleNewCTR() {
|
||||
key := []byte("example key 1234")
|
||||
plaintext := []byte("some plaintext")
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
// It's important to remember that ciphertexts must be authenticated
|
||||
// (i.e. by using crypto/hmac) as well as being encrypted in order to
|
||||
// be secure.
|
||||
|
||||
// CTR mode is the same for both encryption and decryption, so we can
|
||||
// also decrypt that ciphertext with NewCTR.
|
||||
|
||||
plaintext2 := make([]byte, len(plaintext))
|
||||
stream = cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
|
||||
|
||||
fmt.Printf("%s\n", plaintext2)
|
||||
// Output: some plaintext
|
||||
}
|
||||
|
||||
func ExampleNewOFB() {
|
||||
key := []byte("example key 1234")
|
||||
plaintext := []byte("some plaintext")
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
// It's important to remember that ciphertexts must be authenticated
|
||||
// (i.e. by using crypto/hmac) as well as being encrypted in order to
|
||||
// be secure.
|
||||
|
||||
// OFB mode is the same for both encryption and decryption, so we can
|
||||
// also decrypt that ciphertext with NewOFB.
|
||||
|
||||
plaintext2 := make([]byte, len(plaintext))
|
||||
stream = cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
|
||||
|
||||
fmt.Printf("%s\n", plaintext2)
|
||||
// Output: some plaintext
|
||||
}
|
||||
|
||||
func ExampleStreamReader() {
|
||||
key := []byte("example key 1234")
|
||||
|
||||
inFile, err := os.Open("encrypted-file")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer inFile.Close()
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// If the key is unique for each ciphertext, then it's ok to use a zero
|
||||
// IV.
|
||||
var iv [aes.BlockSize]byte
|
||||
stream := cipher.NewOFB(block, iv[:])
|
||||
|
||||
outFile, err := os.OpenFile("decrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
reader := &cipher.StreamReader{S: stream, R: inFile}
|
||||
// Copy the input file to the output file, decrypting as we go.
|
||||
if _, err := io.Copy(outFile, reader); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Note that this example is simplistic in that it omits any
|
||||
// authentication of the encrypted data. If you were actually to use
|
||||
// StreamReader in this manner, an attacker could flip arbitrary bits in
|
||||
// the output.
|
||||
}
|
||||
|
||||
func ExampleStreamWriter() {
|
||||
key := []byte("example key 1234")
|
||||
|
||||
inFile, err := os.Open("plaintext-file")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer inFile.Close()
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// If the key is unique for each ciphertext, then it's ok to use a zero
|
||||
// IV.
|
||||
var iv [aes.BlockSize]byte
|
||||
stream := cipher.NewOFB(block, iv[:])
|
||||
|
||||
outFile, err := os.OpenFile("encrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
writer := &cipher.StreamWriter{S: stream, W: outFile}
|
||||
// Copy the input file to the output file, encrypting as we go.
|
||||
if _, err := io.Copy(writer, inFile); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Note that this example is simplistic in that it omits any
|
||||
// authentication of the encrypted data. If you were actually to use
|
||||
// StreamReader in this manner, an attacker could flip arbitrary bits in
|
||||
// the decrypted result.
|
||||
}
|
435
cipher/gcm_test.go
Normal file
435
cipher/gcm_test.go
Normal file
|
@ -0,0 +1,435 @@
|
|||
// Copyright 2013 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 cipher_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
var aesGCMTests = []struct {
|
||||
key, nonce, plaintext, ad, result string
|
||||
}{
|
||||
{
|
||||
"11754cd72aec309bf52f7687212e8957",
|
||||
"3c819d9a9bed087615030b65",
|
||||
"",
|
||||
"",
|
||||
"250327c674aaf477aef2675748cf6971",
|
||||
},
|
||||
{
|
||||
"ca47248ac0b6f8372a97ac43508308ed",
|
||||
"ffd2b598feabc9019262d2be",
|
||||
"",
|
||||
"",
|
||||
"60d20404af527d248d893ae495707d1a",
|
||||
},
|
||||
{
|
||||
"fbe3467cc254f81be8e78d765a2e6333",
|
||||
"c6697351ff4aec29cdbaabf2",
|
||||
"",
|
||||
"67",
|
||||
"3659cdc25288bf499ac736c03bfc1159",
|
||||
},
|
||||
{
|
||||
"8a7f9d80d08ad0bd5a20fb689c88f9fc",
|
||||
"88b7b27d800937fda4f47301",
|
||||
"",
|
||||
"50edd0503e0d7b8c91608eb5a1",
|
||||
"ed6f65322a4740011f91d2aae22dd44e",
|
||||
},
|
||||
{
|
||||
"051758e95ed4abb2cdc69bb454110e82",
|
||||
"c99a66320db73158a35a255d",
|
||||
"",
|
||||
"67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339f",
|
||||
"6ce77f1a5616c505b6aec09420234036",
|
||||
},
|
||||
{
|
||||
"77be63708971c4e240d1cb79e8d77feb",
|
||||
"e0e00f19fed7ba0136a797f3",
|
||||
"",
|
||||
"7a43ec1d9c0a5a78a0b16533a6213cab",
|
||||
"209fcc8d3675ed938e9c7166709dd946",
|
||||
},
|
||||
{
|
||||
"7680c5d3ca6154758e510f4d25b98820",
|
||||
"f8f105f9c3df4965780321f8",
|
||||
"",
|
||||
"c94c410194c765e3dcc7964379758ed3",
|
||||
"94dca8edfcf90bb74b153c8d48a17930",
|
||||
},
|
||||
{
|
||||
"7fddb57453c241d03efbed3ac44e371c",
|
||||
"ee283a3fc75575e33efd4887",
|
||||
"d5de42b461646c255c87bd2962d3b9a2",
|
||||
"",
|
||||
"2ccda4a5415cb91e135c2a0f78c9b2fdb36d1df9b9d5e596f83e8b7f52971cb3",
|
||||
},
|
||||
{
|
||||
"ab72c77b97cb5fe9a382d9fe81ffdbed",
|
||||
"54cc7dc2c37ec006bcc6d1da",
|
||||
"007c5e5b3e59df24a7c355584fc1518d",
|
||||
"",
|
||||
"0e1bde206a07a9c2c1b65300f8c649972b4401346697138c7a4891ee59867d0c",
|
||||
},
|
||||
{
|
||||
"fe47fcce5fc32665d2ae399e4eec72ba",
|
||||
"5adb9609dbaeb58cbd6e7275",
|
||||
"7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1b840382c4bccaf3bafb4ca8429bea063",
|
||||
"88319d6e1d3ffa5f987199166c8a9b56c2aeba5a",
|
||||
"98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf5393043736365253ddbc5db8778371495da76d269e5db3e291ef1982e4defedaa2249f898556b47",
|
||||
},
|
||||
{
|
||||
"ec0c2ba17aa95cd6afffe949da9cc3a8",
|
||||
"296bce5b50b7d66096d627ef",
|
||||
"b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987b764b9611f6c0f8641843d5d58f3a242",
|
||||
"f8d00f05d22bf68599bcdeb131292ad6e2df5d14",
|
||||
"a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a07162995506fde6309ffc19e716eddf1a828c5a890147971946b627c40016da1ecf3e77",
|
||||
},
|
||||
{
|
||||
"2c1f21cf0f6fb3661943155c3e3d8492",
|
||||
"23cb5ff362e22426984d1907",
|
||||
"42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d68b5615ba7c1220ff6510e259f06655d8",
|
||||
"5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f4488f33cfb5e979e42b6e1cfc0a60238982a7aec",
|
||||
"81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222b6ad57af43e1895df9dca2a5344a62cc57a3ee28136e94c74838997ae9823f3a",
|
||||
},
|
||||
{
|
||||
"d9f7d2411091f947b4d6f1e2d1f0fb2e",
|
||||
"e1934f5db57cc983e6b180e7",
|
||||
"73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490c2c6f6166f4a59431e182663fcaea05a",
|
||||
"0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a20115d2e51398344b16bee1ed7c499b353d6c597af8",
|
||||
"aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d573c7891c2a91fbc48db29967ec9542b2321b51ca862cb637cdd03b99a0f93b134",
|
||||
},
|
||||
{
|
||||
"fe9bb47deb3a61e423c2231841cfd1fb",
|
||||
"4d328eb776f500a2f7fb47aa",
|
||||
"f1cc3818e421876bb6b8bbd6c9",
|
||||
"",
|
||||
"b88c5c1977b35b517b0aeae96743fd4727fe5cdb4b5b42818dea7ef8c9",
|
||||
},
|
||||
{
|
||||
"6703df3701a7f54911ca72e24dca046a",
|
||||
"12823ab601c350ea4bc2488c",
|
||||
"793cd125b0b84a043e3ac67717",
|
||||
"",
|
||||
"b2051c80014f42f08735a7b0cd38e6bcd29962e5f2c13626b85a877101",
|
||||
},
|
||||
// These cases test non-standard nonce sizes.
|
||||
{
|
||||
"1672c3537afa82004c6b8a46f6f0d026",
|
||||
"05",
|
||||
"",
|
||||
"",
|
||||
"8e2ad721f9455f74d8b53d3141f27e8e",
|
||||
},
|
||||
{
|
||||
"9a4fea86a621a91ab371e492457796c0",
|
||||
"75",
|
||||
"ca6131faf0ff210e4e693d6c31c109fc5b6f54224eb120f37de31dc59ec669b6",
|
||||
"4f6e2585c161f05a9ae1f2f894e9f0ab52b45d0f",
|
||||
"5698c0a384241d30004290aac56bb3ece6fe8eacc5c4be98954deb9c3ff6aebf5d50e1af100509e1fba2a5e8a0af9670",
|
||||
},
|
||||
{
|
||||
"d0f1f4defa1e8c08b4b26d576392027c",
|
||||
"42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
|
||||
"",
|
||||
"",
|
||||
"7ab49b57ddf5f62c427950111c5c4f0d",
|
||||
},
|
||||
{
|
||||
"4a0c00a3d284dea9d4bf8b8dde86685e",
|
||||
"f8cbe82588e784bcacbe092cd9089b51e01527297f635bf294b3aa787d91057ef23869789698ac960707857f163ecb242135a228ad93964f5dc4a4d7f88fd7b3b07dd0a5b37f9768fb05a523639f108c34c661498a56879e501a2321c8a4a94d7e1b89db255ac1f685e185263368e99735ebe62a7f2931b47282be8eb165e4d7",
|
||||
"6d4bf87640a6a48a50d28797b7",
|
||||
"8d8c7ffc55086d539b5a8f0d1232654c",
|
||||
"0d803ec309482f35b8e6226f2b56303239298e06b281c2d51aaba3c125",
|
||||
},
|
||||
{
|
||||
"0e18a844ac5bf38e4cd72d9b0942e506",
|
||||
"0870d4b28a2954489a0abcd5",
|
||||
"67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b3",
|
||||
"05eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea9",
|
||||
"cace28f4976afd72e3c5128167eb788fbf6634dda0a2f53148d00f6fa557f5e9e8f736c12e450894af56cb67f7d99e1027258c8571bd91ee3b7360e0d508aa1f382411a16115f9c05251cc326d4016f62e0eb8151c048465b0c6c8ff12558d43310e18b2cb1889eec91557ce21ba05955cf4c1d4847aadfb1b0a83f3a3b82b7efa62a5f03c5d6eda381a85dd78dbc55c",
|
||||
},
|
||||
{
|
||||
"1f6c3a3bc0542aabba4ef8f6c7169e73",
|
||||
"f3584606472b260e0dd2ebb2",
|
||||
"67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9bbce9e525cf08f5e9e25e5360aad2b2d085fa54d835e8d466826498d9a8877565705a8a3f62802944de7ca5894e5759d351adac869580ec17e485f18c0c66f17cc07cbb22fce466da610b63af62bc83b4692f3affaf271693ac071fb86d11342d8def4f89d4b66335c1c7e4248367d8ed9612ec453902d8e50af89d7709d1a596c1f41f",
|
||||
"95aa82ca6c49ae90cd1668baac7aa6f2b4a8ca99b2c2372acb08cf61c9c3805e6e0328da4cd76a19edd2d3994c798b0022569ad418d1fee4d9cd45a391c601ffc92ad91501432fee150287617c13629e69fc7281cd7165a63eab49cf714bce3a75a74f76ea7e64ff81eb61fdfec39b67bf0de98c7e4e32bdf97c8c6ac75ba43c02f4b2ed7216ecf3014df000108b67cf99505b179f8ed4980a6103d1bca70dbe9bbfab0ed59801d6e5f2d6f67d3ec5168e212e2daf02c6b963c98a1f7097de0c56891a2b211b01070dd8fd8b16c2a1a4e3cfd292d2984b3561d555d16c33ddc2bcf7edde13efe520c7e2abdda44d81881c531aeeeb66244c3b791ea8acfb6a68",
|
||||
"55864065117e07650ca650a0f0d9ef4b02aee7c58928462fddb49045bf85355b4653fa26158210a7f3ef5b3ca48612e8b7adf5c025c1b821960af770d935df1c9a1dd25077d6b1c7f937b2e20ce981b07980880214698f3fad72fa370b3b7da257ce1d0cf352bc5304fada3e0f8927bd4e5c1abbffa563bdedcb567daa64faaed748cb361732200ba3506836a3c1c82aafa14c76dc07f6c4277ff2c61325f91fdbd6c1883e745fcaadd5a6d692eeaa5ad56eead6a9d74a595d22757ed89532a4b8831e2b9e2315baea70a9b95d228f09d491a5ed5ab7076766703457e3159bbb9b17b329525669863153079448c68cd2f200c0be9d43061a60639cb59d50993d276c05caaa565db8ce633b2673e4012bebbca02b1a64d779d04066f3e949ece173825885ec816468c819a8129007cc05d8785c48077d09eb1abcba14508dde85a6f16a744bc95faef24888d53a8020515ab20307efaecbdf143a26563c67989bceedc2d6d2bb9699bb6c615d93767e4158c1124e3b6c723aaa47796e59a60d3696cd85adfae9a62f2c02c22009f80ed494bdc587f31dd892c253b5c6d6b7db078fa72d23474ee54f8144d6561182d71c862941dbc0b2cb37a4d4b23cbad5637e6be901cc73f16d5aec39c60dddee631511e57b47520b61ae1892d2d1bd2b486e30faec892f171b6de98d96108016fac805604761f8e74742b3bb7dc8a290a46bf697c3e4446e6e65832cbae7cf1aaad1",
|
||||
},
|
||||
{
|
||||
"0795d80bc7f40f4d41c280271a2e4f7f",
|
||||
"ff824c906594aff365d3cb1f",
|
||||
"1ad4e74d127f935beee57cff920665babe7ce56227377afe570ba786193ded3412d4812453157f42fafc418c02a746c1232c234a639d49baa8f041c12e2ef540027764568ce49886e0d913e28059a3a485c6eee96337a30b28e4cd5612c2961539fa6bc5de034cbedc5fa15db844013e0bef276e27ca7a4faf47a5c1093bd643354108144454d221b3737e6cb87faac36ed131959babe44af2890cfcc4e23ffa24470e689ce0894f5407bb0c8665cff536008ad2ac6f1c9ef8289abd0bd9b72f21c597bda5210cf928c805af2dd4a464d52e36819d521f967bba5386930ab5b4cf4c71746d7e6e964673457348e9d71d170d9eb560bd4bdb779e610ba816bf776231ebd0af5966f5cdab6815944032ab4dd060ad8dab880549e910f1ffcf6862005432afad",
|
||||
"98a47a430d8fd74dc1829a91e3481f8ed024d8ba34c9b903321b04864db333e558ae28653dffb2",
|
||||
"3b8f91443480e647473a0a0b03d571c622b7e70e4309a02c9bb7980053010d865e6aec161354dc9f481b2cd5213e09432b57ec4e58fbd0a8549dd15c8c4e74a6529f75fad0ce5a9e20e2beeb2f91eb638bf88999968de438d2f1cedbfb0a1c81f9e8e7362c738e0fddd963692a4f4df9276b7f040979ce874cf6fa3de26da0713784bdb25e4efcb840554ef5b38b5fe8380549a496bd8e423a7456df6f4ae78a07ebe2276a8e22fc2243ec4f78abe0c99c733fd67c8c492699fa5ee2289cdd0a8d469bf883520ee74efb854bfadc7366a49ee65ca4e894e3335e2b672618d362eee12a577dd8dc2ba55c49c1fc3ad68180e9b112d0234d4aa28f5661f1e036450ca6f18be0166676bd80f8a4890c6ddea306fabb7ff3cb2860aa32a827e3a312912a2dfa70f6bc1c07de238448f2d751bd0cf15bf7",
|
||||
},
|
||||
{
|
||||
"e2e001a36c60d2bf40d69ff5b2b1161ea218db263be16a4e",
|
||||
"84230643130d05425826641e",
|
||||
"adb034f3f4a7ca45e2993812d113a9821d50df151af978bccc6d3bc113e15bc0918fb385377dca1916022ce816d56a332649484043c0fc0f2d37d040182b00a9bbb42ef231f80b48fb3730110d9a4433e38c73264c703579a705b9c031b969ec6d98de9f90e9e78b21179c2eb1e061946cd4bbb844f031ecf6eaac27a4151311adf1b03eda97c9fbae66295f468af4b35faf6ba39f9d8f95873bbc2b51cf3dfec0ed3c9b850696336cc093b24a8765a936d14dd56edc6bf518272169f75e67b74ba452d0aae90416a997c8f31e2e9d54ffea296dc69462debc8347b3e1af6a2d53bdfdfda601134f98db42b609df0a08c9347590c8d86e845bb6373d65a26ab85f67b50569c85401a396b8ad76c2b53ff62bcfbf033e435ef47b9b591d05117c6dc681d68e",
|
||||
"d5d7316b8fdee152942148bff007c22e4b2022c6bc7be3c18c5f2e52e004e0b5dc12206bf002bd",
|
||||
"f2c39423ee630dfe961da81909159dba018ce09b1073a12a477108316af5b7a31f86be6a0548b572d604bd115ea737dde899e0bd7f7ac9b23e38910dc457551ecc15c814a9f46d8432a1a36097dc1afe2712d1ba0838fa88cb55d9f65a2e9bece0dbf8999562503989041a2c87d7eb80ef649769d2f4978ce5cf9664f2bd0849646aa81cb976e45e1ade2f17a8126219e917aadbb4bae5e2c4b3f57bbc7f13fcc807df7842d9727a1b389e0b749e5191482adacabd812627c6eae2c7a30caf0844ad2a22e08f39edddf0ae10413e47db433dfe3febbb5a5cec9ade21fbba1e548247579395880b747669a8eb7e2ec0c1bff7fed2defdb92b07a14edf07b1bde29c31ab052ff1214e6b5ebbefcb8f21b5d6f8f6e07ee57ad6e14d4e142cb3f51bb465ab3a28a2a12f01b7514ad0463f2bde0d71d221",
|
||||
},
|
||||
{
|
||||
"5394e890d37ba55ec9d5f327f15680f6a63ef5279c79331643ad0af6d2623525",
|
||||
"815e840b7aca7af3b324583f",
|
||||
"8e63067cd15359f796b43c68f093f55fdf3589fc5f2fdfad5f9d156668a617f7091d73da71cdd207810e6f71a165d0809a597df9885ca6e8f9bb4e616166586b83cc45f49917fc1a256b8bc7d05c476ab5c4633e20092619c4747b26dad3915e9fd65238ee4e5213badeda8a3a22f5efe6582d0762532026c89b4ca26fdd000eb45347a2a199b55b7790e6b1b2dba19833ce9f9522c0bcea5b088ccae68dd99ae0203c81b9f1dd3181c3e2339e83ccd1526b67742b235e872bea5111772aab574ae7d904d9b6355a79178e179b5ae8edc54f61f172bf789ea9c9af21f45b783e4251421b077776808f04972a5e801723cf781442378ce0e0568f014aea7a882dcbcb48d342be53d1c2ebfb206b12443a8a587cc1e55ca23beca385d61d0d03e9d84cbc1b0a",
|
||||
"0feccdfae8ed65fa31a0858a1c466f79e8aa658c2f3ba93c3f92158b4e30955e1c62580450beff",
|
||||
"b69a7e17bb5af688883274550a4ded0d1aff49a0b18343f4b382f745c163f7f714c9206a32a1ff012427e19431951edd0a755e5f491b0eedfd7df68bbc6085dd2888607a2f998c3e881eb1694109250db28291e71f4ad344a125624fb92e16ea9815047cd1111cabfdc9cb8c3b4b0f40aa91d31774009781231400789ed545404af6c3f76d07ddc984a7bd8f52728159782832e298cc4d529be96d17be898efd83e44dc7b0e2efc645849fd2bba61fef0ae7be0dcab233cc4e2b7ba4e887de9c64b97f2a1818aa54371a8d629dae37975f7784e5e3cc77055ed6e975b1e5f55e6bbacdc9f295ce4ada2c16113cd5b323cf78b7dde39f4a87aa8c141a31174e3584ccbd380cf5ec6d1dba539928b084fa9683e9c0953acf47cc3ac384a2c38914f1da01fb2cfd78905c2b58d36b2574b9df15535d82",
|
||||
},
|
||||
}
|
||||
|
||||
func TestAESGCM(t *testing.T) {
|
||||
for i, test := range aesGCMTests {
|
||||
key, _ := hex.DecodeString(test.key)
|
||||
aes, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nonce, _ := hex.DecodeString(test.nonce)
|
||||
plaintext, _ := hex.DecodeString(test.plaintext)
|
||||
ad, _ := hex.DecodeString(test.ad)
|
||||
aesgcm, err := cipher.NewGCMWithNonceSize(aes, len(nonce))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ct := aesgcm.Seal(nil, nonce, plaintext, ad)
|
||||
if ctHex := hex.EncodeToString(ct); ctHex != test.result {
|
||||
t.Errorf("#%d: got %s, want %s", i, ctHex, test.result)
|
||||
continue
|
||||
}
|
||||
|
||||
plaintext2, err := aesgcm.Open(nil, nonce, ct, ad)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: Open failed", i)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(plaintext, plaintext2) {
|
||||
t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(ad) > 0 {
|
||||
ad[0] ^= 0x80
|
||||
if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering additional data", i)
|
||||
}
|
||||
ad[0] ^= 0x80
|
||||
}
|
||||
|
||||
nonce[0] ^= 0x80
|
||||
if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering nonce", i)
|
||||
}
|
||||
nonce[0] ^= 0x80
|
||||
|
||||
ct[0] ^= 0x80
|
||||
if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering ciphertext", i)
|
||||
}
|
||||
ct[0] ^= 0x80
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagFailureOverwrite(t *testing.T) {
|
||||
// The AESNI GCM code decrypts and authenticates concurrently and so
|
||||
// overwrites the output buffer before checking the authentication tag.
|
||||
// In order to be consistent across platforms, all implementations
|
||||
// should do this and this test checks that.
|
||||
|
||||
key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
|
||||
nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db")
|
||||
ciphertext, _ := hex.DecodeString("0e1bde206a07a9c2c1b65300f8c649972b4401346697138c7a4891ee59867d0c")
|
||||
|
||||
aes, _ := aes.NewCipher(key)
|
||||
aesgcm, _ := cipher.NewGCM(aes)
|
||||
|
||||
dst := make([]byte, len(ciphertext)-16)
|
||||
for i := range dst {
|
||||
dst[i] = 42
|
||||
}
|
||||
|
||||
result, err := aesgcm.Open(dst[:0], nonce, ciphertext, nil)
|
||||
if err == nil {
|
||||
t.Fatal("Bad Open still resulted in nil error.")
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
t.Fatal("Failed Open returned non-nil result.")
|
||||
}
|
||||
|
||||
for i := range dst {
|
||||
if dst[i] != 0 {
|
||||
t.Fatal("Failed Open didn't zero dst buffer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCMCounterWrap(t *testing.T) {
|
||||
// Test that the last 32-bits of the counter wrap correctly.
|
||||
tests := []struct {
|
||||
nonce, tag string
|
||||
}{
|
||||
{"0fa72e25", "37e1948cdfff09fbde0c40ad99fee4a7"}, // counter: 7eb59e4d961dad0dfdd75aaffffffff0
|
||||
{"afe05cc1", "438f3aa9fee5e54903b1927bca26bbdf"}, // counter: 75d492a7e6e6bfc979ad3a8ffffffff4
|
||||
{"9ffecbef", "7b88ca424df9703e9e8611071ec7e16e"}, // counter: c8bb108b0ecdc71747b9d57ffffffff5
|
||||
{"ffc3e5b3", "38d49c86e0abe853ac250e66da54c01a"}, // counter: 706414d2de9b36ab3b900a9ffffffff6
|
||||
{"cfdd729d", "e08402eaac36a1a402e09b1bd56500e8"}, // counter: cd0b96fe36b04e750584e56ffffffff7
|
||||
{"010ae3d486", "5405bb490b1f95d01e2ba735687154bc"}, // counter: e36c18e69406c49722808104fffffff8
|
||||
{"01b1107a9d", "939a585f342e01e17844627492d44dbf"}, // counter: e6d56eaf9127912b6d62c6dcffffffff
|
||||
}
|
||||
key, err := aes.NewCipher(make([]byte, 16))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plaintext := make([]byte, 16*17+1)
|
||||
for i, test := range tests {
|
||||
nonce, _ := hex.DecodeString(test.nonce)
|
||||
want, _ := hex.DecodeString(test.tag)
|
||||
aead, err := cipher.NewGCMWithNonceSize(key, len(nonce))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := aead.Seal(nil, nonce, plaintext, nil)
|
||||
if !bytes.Equal(got[len(plaintext):], want) {
|
||||
t.Errorf("test[%v]: got: %x, want: %x", i, got[len(plaintext):], want)
|
||||
}
|
||||
_, err = aead.Open(nil, nonce, got, nil)
|
||||
if err != nil {
|
||||
t.Errorf("test[%v]: authentication failed", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ cipher.Block = (*wrapper)(nil)
|
||||
|
||||
type wrapper struct {
|
||||
block cipher.Block
|
||||
}
|
||||
|
||||
func (w *wrapper) BlockSize() int { return w.block.BlockSize() }
|
||||
func (w *wrapper) Encrypt(dst, src []byte) { w.block.Encrypt(dst, src) }
|
||||
func (w *wrapper) Decrypt(dst, src []byte) { w.block.Decrypt(dst, src) }
|
||||
|
||||
// wrap wraps the Block interface so that it does not fulfill
|
||||
// any optimizing interfaces such as gcmAble.
|
||||
func wrap(b cipher.Block) cipher.Block {
|
||||
return &wrapper{b}
|
||||
}
|
||||
|
||||
func TestGCMAsm(t *testing.T) {
|
||||
// Create a new pair of AEADs, one using the assembly implementation
|
||||
// and one using the generic Go implementation.
|
||||
newAESGCM := func(key []byte) (asm, generic cipher.AEAD, err error) {
|
||||
block, err := aes.NewCipher(key[:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
asm, err = cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
generic, err = cipher.NewGCM(wrap(block))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return asm, generic, nil
|
||||
}
|
||||
|
||||
// check for assembly implementation
|
||||
var key [16]byte
|
||||
asm, generic, err := newAESGCM(key[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if reflect.TypeOf(asm) == reflect.TypeOf(generic) {
|
||||
t.Skipf("no assembly implementation of GCM")
|
||||
}
|
||||
|
||||
// generate permutations
|
||||
type pair struct{ align, length int }
|
||||
lengths := []int{0, 8192, 8193, 8208}
|
||||
keySizes := []int{16, 24, 32}
|
||||
alignments := []int{0, 1, 2, 3}
|
||||
if testing.Short() {
|
||||
keySizes = []int{16}
|
||||
alignments = []int{1}
|
||||
}
|
||||
perms := make([]pair, 0)
|
||||
for _, l := range lengths {
|
||||
for _, a := range alignments {
|
||||
if a != 0 && l == 0 {
|
||||
continue
|
||||
}
|
||||
perms = append(perms, pair{align: a, length: l})
|
||||
}
|
||||
}
|
||||
|
||||
// run test for all permutations
|
||||
test := func(ks int, pt, ad []byte) error {
|
||||
key := make([]byte, ks)
|
||||
if _, err := io.ReadFull(rand.Reader, key); err != nil {
|
||||
return err
|
||||
}
|
||||
asm, generic, err := newAESGCM(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.ReadFull(rand.Reader, pt); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.ReadFull(rand.Reader, ad); err != nil {
|
||||
return err
|
||||
}
|
||||
nonce := make([]byte, 12)
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return err
|
||||
}
|
||||
want := generic.Seal(nil, nonce, pt, ad)
|
||||
got := asm.Seal(nil, nonce, pt, ad)
|
||||
if !bytes.Equal(want, got) {
|
||||
return errors.New("incorrect Seal output")
|
||||
}
|
||||
got, err = asm.Open(nil, nonce, want, ad)
|
||||
if err != nil {
|
||||
return errors.New("authentication failed")
|
||||
}
|
||||
if !bytes.Equal(pt, got) {
|
||||
return errors.New("incorrect Open output")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for _, a := range perms {
|
||||
ad := make([]byte, a.align+a.length)
|
||||
ad = ad[a.align:]
|
||||
for _, p := range perms {
|
||||
pt := make([]byte, p.align+p.length)
|
||||
pt = pt[p.align:]
|
||||
for _, ks := range keySizes {
|
||||
if err := test(ks, pt, ad); err != nil {
|
||||
t.Error(err)
|
||||
t.Errorf(" key size: %v", ks)
|
||||
t.Errorf(" plaintext alignment: %v", p.align)
|
||||
t.Errorf(" plaintext length: %v", p.length)
|
||||
t.Errorf(" additionalData alignment: %v", a.align)
|
||||
t.Fatalf(" additionalData length: %v", a.length)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
103
cipher/ofb_test.go
Normal file
103
cipher/ofb_test.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2009 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.
|
||||
|
||||
// OFB AES test vectors.
|
||||
|
||||
// See U.S. National Institute of Standards and Technology (NIST)
|
||||
// Special Publication 800-38A, ``Recommendation for Block Cipher
|
||||
// Modes of Operation,'' 2001 Edition, pp. 52-55.
|
||||
|
||||
package cipher_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"testing"
|
||||
|
||||
"github.com/stacktic/cryptodev/aes"
|
||||
)
|
||||
|
||||
type ofbTest struct {
|
||||
name string
|
||||
key []byte
|
||||
iv []byte
|
||||
in []byte
|
||||
out []byte
|
||||
}
|
||||
|
||||
var ofbTests = []ofbTest{
|
||||
// NIST SP 800-38A pp 52-55
|
||||
{
|
||||
"OFB-AES128",
|
||||
commonKey128,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
|
||||
0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
|
||||
0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
|
||||
0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
|
||||
},
|
||||
},
|
||||
{
|
||||
"OFB-AES192",
|
||||
commonKey192,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
|
||||
0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
|
||||
0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
|
||||
0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
|
||||
},
|
||||
},
|
||||
{
|
||||
"OFB-AES256",
|
||||
commonKey256,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
|
||||
0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
|
||||
0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
|
||||
0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestOFB(t *testing.T) {
|
||||
for _, tt := range ofbTests {
|
||||
test := tt.name
|
||||
|
||||
c, err := aes.NewCipher(tt.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 0; j <= 5; j += 5 {
|
||||
plaintext := tt.in[0 : len(tt.in)-j]
|
||||
ofb := cipher.NewOFB(c, tt.iv)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
ofb.XORKeyStream(ciphertext, plaintext)
|
||||
if !bytes.Equal(ciphertext, tt.out[:len(plaintext)]) {
|
||||
t.Errorf("%s/%d: encrypting\ninput % x\nhave % x\nwant % x", test, len(plaintext), plaintext, ciphertext, tt.out)
|
||||
}
|
||||
}
|
||||
|
||||
for j := 0; j <= 5; j += 5 {
|
||||
ciphertext := tt.out[0 : len(tt.in)-j]
|
||||
ofb := cipher.NewOFB(c, tt.iv)
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
ofb.XORKeyStream(plaintext, ciphertext)
|
||||
if !bytes.Equal(plaintext, tt.in[:len(ciphertext)]) {
|
||||
t.Errorf("%s/%d: decrypting\nhave % x\nwant % x", test, len(ciphertext), plaintext, tt.in)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
209
cryptodev/cryptodev.go
Normal file
209
cryptodev/cryptodev.go
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
** Copyright (c) 2017 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package cryptodev
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
fd *os.File
|
||||
sfd int = -1
|
||||
)
|
||||
|
||||
const (
|
||||
COP_ENCRYPT = 1
|
||||
COP_DECRYPT = 2
|
||||
COP_F_BATCH = 0x0008 /* Batch op if possible */
|
||||
|
||||
CRYPTO_DES_CBC = 1
|
||||
CRYPTO_3DES_CBC = 2
|
||||
CRYPTO_BLF_CBC = 3
|
||||
CRYPTO_CAST_CBC = 4
|
||||
CRYPTO_SKIPJACK_CBC = 5
|
||||
CRYPTO_MD5_HMAC = 6
|
||||
CRYPTO_SHA1_HMAC = 7
|
||||
CRYPTO_RIPEMD160_HMAC = 8
|
||||
CRYPTO_MD5_KPDK = 9
|
||||
CRYPTO_SHA1_KPDK = 10
|
||||
CRYPTO_RIJNDAEL128_CBC = 11 /* 128 bit blocksize */
|
||||
CRYPTO_AES_CBC = 11 /* 128 bit blocksize -- the same as above */
|
||||
CRYPTO_ARC4 = 12
|
||||
CRYPTO_MD5 = 13
|
||||
CRYPTO_SHA1 = 14
|
||||
CRYPTO_NULL_HMAC = 15
|
||||
CRYPTO_NULL_CBC = 16
|
||||
CRYPTO_DEFLATE_COMP = 17 /* Deflate compression algorithm */
|
||||
CRYPTO_SHA2_256_HMAC = 18
|
||||
CRYPTO_SHA2_384_HMAC = 19
|
||||
CRYPTO_SHA2_512_HMAC = 20
|
||||
CRYPTO_CAMELLIA_CBC = 21
|
||||
CRYPTO_AES_XTS = 22
|
||||
CRYPTO_AES_ICM = 23 /* commonly known as CTR mode */
|
||||
CRYPTO_AES_NIST_GMAC = 24 /* cipher side */
|
||||
CRYPTO_AES_NIST_GCM_16 = 25 /* 16 byte ICV */
|
||||
CRYPTO_AES_128_NIST_GMAC = 26 /* auth side */
|
||||
CRYPTO_AES_192_NIST_GMAC = 27 /* auth side */
|
||||
CRYPTO_AES_256_NIST_GMAC = 28 /* auth side */
|
||||
|
||||
CRIOGET = uint32(0xc0046364)
|
||||
CRIOASYMFEAT = uint32(0x40046369)
|
||||
CRIOFINDDEV = uint32(0xc024636c)
|
||||
CIOCGSESSION = uint32(0xc01c6365)
|
||||
CIOCFSESSION = uint32(0x80046366)
|
||||
CIOCCRYPT = uint32(0xc01c6367)
|
||||
CIOCKEY = uint32(0xc0506368)
|
||||
CIOCASYMFEAT = uint32(0x40046369)
|
||||
CIOCGSESSION2 = uint32(0xc030636a)
|
||||
CIOCKEY2 = uint32(0xc050636b)
|
||||
CIOCFINDDEV = uint32(0xc024636c)
|
||||
CIOCCRYPTAEAD = uint32(0xc028636d)
|
||||
)
|
||||
|
||||
type session_op struct {
|
||||
cipher uint32
|
||||
mac uint32
|
||||
keylen uint32
|
||||
key uintptr
|
||||
mackeylen int
|
||||
mackey uintptr
|
||||
ses uint32
|
||||
}
|
||||
|
||||
type session2_op struct {
|
||||
cipher uint32
|
||||
mac uint32
|
||||
keylen uint32
|
||||
key uintptr
|
||||
mackeylen int
|
||||
mackey uintptr
|
||||
ses uint32
|
||||
crid int
|
||||
pad [4]int
|
||||
}
|
||||
|
||||
type crypt_op struct {
|
||||
ses uint32
|
||||
op uint16
|
||||
flags uint16
|
||||
len uint
|
||||
src uintptr
|
||||
dst uintptr
|
||||
mac uintptr
|
||||
iv uintptr
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
s uint32
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
var errno syscall.Errno
|
||||
|
||||
fd, err = os.OpenFile("/dev/crypto", os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _, errno = syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(fd.Fd()), uintptr(CRIOGET), uintptr(unsafe.Pointer(&sfd)))
|
||||
if errno != 0 {
|
||||
fini()
|
||||
return
|
||||
}
|
||||
_, _, errno = syscall.RawSyscall(syscall.SYS_FCNTL, uintptr(sfd), syscall.F_SETFD, uintptr(1))
|
||||
if errno != 0 {
|
||||
fini()
|
||||
}
|
||||
}
|
||||
|
||||
func fini() {
|
||||
if sfd != -1 {
|
||||
syscall.Close(sfd)
|
||||
sfd = -1
|
||||
}
|
||||
if fd != nil {
|
||||
fd.Close()
|
||||
fd = nil
|
||||
}
|
||||
}
|
||||
|
||||
func closeSession(s *Session) {
|
||||
syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(sfd), uintptr(CIOCFSESSION), uintptr(unsafe.Pointer(&s)))
|
||||
}
|
||||
|
||||
func NewSession(cipher uint32, key []byte) (*Session, error) {
|
||||
var cs session_op
|
||||
|
||||
cs.cipher = cipher
|
||||
cs.keylen = uint32(len(key))
|
||||
cs.key = uintptr(unsafe.Pointer(&key[0]))
|
||||
_, _, errno := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(sfd), uintptr(CIOCGSESSION), uintptr(unsafe.Pointer(&cs)))
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
s := &Session{cs.ses}
|
||||
runtime.SetFinalizer(s, closeSession)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s Session) Encrypt(dst []byte, src []byte, iv []byte) error {
|
||||
var co crypt_op
|
||||
var errno syscall.Errno
|
||||
|
||||
co.ses = s.s
|
||||
co.op = COP_ENCRYPT
|
||||
co.len = uint(len(src))
|
||||
co.src = uintptr(unsafe.Pointer(&src[0]))
|
||||
co.dst = uintptr(unsafe.Pointer(&dst[0]))
|
||||
co.iv = uintptr(unsafe.Pointer(&iv[0]))
|
||||
|
||||
_, _, errno = syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(sfd), uintptr(CIOCCRYPT), uintptr(unsafe.Pointer(&co)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Session) Decrypt(dst []byte, src []byte, iv []byte) error {
|
||||
var co crypt_op
|
||||
var errno syscall.Errno
|
||||
|
||||
co.ses = s.s
|
||||
co.op = COP_DECRYPT
|
||||
co.len = uint(len(src))
|
||||
co.src = uintptr(unsafe.Pointer(&src[0]))
|
||||
co.dst = uintptr(unsafe.Pointer(&dst[0]))
|
||||
co.iv = uintptr(unsafe.Pointer(&iv[0]))
|
||||
|
||||
_, _, errno = syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(sfd), uintptr(CIOCCRYPT), uintptr(unsafe.Pointer(&co)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user