Skip to content

Commit

Permalink
HSM-native GCM
Browse files Browse the repository at this point in the history
For testing with SoftHSM2 you need at least version 2.4.0, i.e. at least
Debian buster/sid or Ubuntu cosmic (or BYO).

This commit also updates our dependency on github.com/miekg/pkcs11 to
one with GCM support.

re #6
  • Loading branch information
Richard Kettlewell authored and Richard Kettlewell committed Aug 3, 2018
1 parent 964aebf commit cfa51e0
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 3 deletions.
4 changes: 2 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ To protect keys with the module only, use the 'accelerator' token:
"Pin" : "password"
}

(At time of writing) GCM is not implemented, so expect test skips.

Testing with SoftHSM
--------------------

Expand Down
73 changes: 73 additions & 0 deletions symmetric.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ type SymmetricCipher struct {

// CBC mechanism (CKM_..._CBC)
CBCMech uint

// GCM mechanism (CKM_..._GCM)
GCMMech uint
}

// CipherAES describes the AES cipher. Use this with the
Expand All @@ -63,6 +66,7 @@ var CipherAES = SymmetricCipher{
MAC: false,
ECBMech: pkcs11.CKM_AES_ECB,
CBCMech: pkcs11.CKM_AES_CBC,
GCMMech: pkcs11.CKM_AES_GCM,
}

// CipherDES3 describes the three-key triple-DES cipher. Use this with the
Expand All @@ -75,6 +79,7 @@ var CipherDES3 = SymmetricCipher{
MAC: false,
ECBMech: pkcs11.CKM_DES3_ECB,
CBCMech: pkcs11.CKM_DES3_CBC,
GCMMech: 0,
}

// Ciphers is a map of PKCS#11 key types (CKK_...) to symmetric cipher information.
Expand Down Expand Up @@ -216,6 +221,74 @@ func (key *PKCS11SecretKey) Encrypt(dst, src []byte) {
}
}

// cipher.AEAD ----------------------------------------------------------

type gcmAead struct {
key *PKCS11SecretKey
}

// NewGCM returns a given cipher wrapped in Galois Counter Mode, with the standard
// nonce length.
//
// This depends on the HSM supporting the CKM_*_GCM mechanism. If it is not supported
// then you must use cipher.NewGCM; it will be slow.
func (key *PKCS11SecretKey) NewGCM() (g cipher.AEAD, err error) {
if key.Cipher.GCMMech == 0 {
err = fmt.Errorf("GCM not implemented for key type %#x", key.Cipher.KeyType)
return
}
g = gcmAead{key}
return
}

func (g gcmAead) NonceSize() int {
return 12
}

func (g gcmAead) Overhead() int {
return 16
}

func (g gcmAead) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
var result []byte
if err := withSession(g.key.Slot, func(session *PKCS11Session) (err error) {
params := pkcs11.NewGCMParams(nonce, additionalData, 16)
mech := []*pkcs11.Mechanism{pkcs11.NewMechanism(g.key.Cipher.GCMMech, params)}
if err = session.Ctx.EncryptInit(session.Handle, mech, g.key.Handle); err != nil {
return
}
if result, err = session.Ctx.Encrypt(session.Handle, plaintext); err != nil {
return
}
return
}); err != nil {
panic(err)
} else {
dst = append(dst, result...)
}
return dst
}

func (g gcmAead) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
var result []byte
if err := withSession(g.key.Slot, func(session *PKCS11Session) (err error) {
params := pkcs11.NewGCMParams(nonce, additionalData, 16)
mech := []*pkcs11.Mechanism{pkcs11.NewMechanism(g.key.Cipher.GCMMech, params)}
if err = session.Ctx.DecryptInit(session.Handle, mech, g.key.Handle); err != nil {
return
}
if result, err = session.Ctx.Decrypt(session.Handle, ciphertext); err != nil {
return
}
return
}); err != nil {
return nil, err
} else {
dst = append(dst, result...)
}
return dst, nil
}

// Stream encryption/decryption -----------------------------------------

// BlockModeCloser represents a block cipher running in a block-based mode (CBC, ECB etc).
Expand Down
21 changes: 20 additions & 1 deletion symmetric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,31 @@ func testHardSymmetric(t *testing.T, keytype int, bits int) {
dec.Close()
})
if bits == 128 {
t.Run("GCM", func(t *testing.T) {
t.Run("GCMSoft", func(t *testing.T) {
aead, err := cipher.NewGCM(key2)
if err != nil {
t.Errorf("cipher.NewGCM: %v", err)
return
}
testAEADMode(t, aead)
})
t.Run("GCMHard", func(t *testing.T) {
var info pkcs11.Info
if info, err = libHandle.GetInfo(); err != nil {
t.Errorf("GetInfo: %v", err)
return
}
if info.ManufacturerID == "nCipher Corp. Ltd" {
t.Skipf("nShield PKCS#11 does not have GCM yet")
}
aead, err := key2.NewGCM()
if err != nil {
t.Errorf("key2.NewGCM: %v", err)
return
}
testAEADMode(t, aead)
})
// TODO check that hard/soft is consistent!
}
// TODO CFB
// TODO OFB
Expand Down Expand Up @@ -240,3 +257,5 @@ func BenchmarkCBC(b *testing.B) {
})
Close()
}

// TODO BenchmarkGCM along the same lines as above

0 comments on commit cfa51e0

Please sign in to comment.