Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions cng/aes.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ func NewAESCipher(key []byte) (cipher.Block, error) {
return nil, err
}
c := &aesCipher{kh: kh, key: bytes.Clone(key)}
addCleanupKey(c, kh)
runtime.SetFinalizer(c, (*aesCipher).finalize)
return c, nil
}

func (c *aesCipher) finalize() {
bcrypt.DestroyKey(c.kh)
}

func (c *aesCipher) BlockSize() int { return aesBlockSize }

// validateAndClipInputs checks that dst and src meet the [cipher.Block]
Expand Down Expand Up @@ -161,11 +165,15 @@ func newCBC(encrypt bool, alg string, key, iv []byte) *cbcCipher {
panic(err)
}
x := &cbcCipher{kh: kh, encrypt: encrypt, blockSize: blockSize}
addCleanupKey(x, kh)
runtime.SetFinalizer(x, (*cbcCipher).finalize)
x.SetIV(iv)
return x
}

func (x *cbcCipher) finalize() {
bcrypt.DestroyKey(x.kh)
}

func (x *cbcCipher) BlockSize() int { return x.blockSize }

func (x *cbcCipher) CryptBlocks(dst, src []byte) {
Expand Down Expand Up @@ -239,13 +247,17 @@ type aesGCM struct {
maskInitialized bool
}

func (g *aesGCM) finalize() {
bcrypt.DestroyKey(g.kh)
}

func newGCM(key []byte, tls cipherGCMTLS) (*aesGCM, error) {
kh, err := newCipherHandle(bcrypt.AES_ALGORITHM, bcrypt.CHAIN_MODE_GCM, key)
if err != nil {
return nil, err
}
g := &aesGCM{kh: kh, tls: tls}
addCleanupKey(g, kh)
runtime.SetFinalizer(g, (*aesGCM).finalize)
return g, nil
}

Expand Down
8 changes: 7 additions & 1 deletion cng/chacha20poly1305.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@ func NewChaCha20Poly1305(key []byte) (cipher.AEAD, error) {
return nil, err
}
c := &chacha20poly1305{kh: kh}
addCleanupKey(c, kh)
runtime.SetFinalizer(c, (*chacha20poly1305).finalize)
return c, nil
}

func (c *chacha20poly1305) finalize() {
if c.kh != 0 {
bcrypt.DestroyKey(c.kh)
}
}

func (c *chacha20poly1305) NonceSize() int {
return chacha20Poly1305NonceSize
}
Expand Down
8 changes: 6 additions & 2 deletions cng/des.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func NewDESCipher(key []byte) (cipher.Block, error) {
return nil, err
}
c := &desCipher{kh: kh, alg: bcrypt.DES_ALGORITHM, key: bytes.Clone(key)}
addCleanupKey(c, kh)
runtime.SetFinalizer(c, (*desCipher).finalize)
return c, nil
}

Expand All @@ -39,10 +39,14 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) {
return nil, err
}
c := &desCipher{kh: kh, alg: bcrypt.DES3_ALGORITHM, key: bytes.Clone(key)}
addCleanupKey(c, kh)
runtime.SetFinalizer(c, (*desCipher).finalize)
return c, nil
}

func (c *desCipher) finalize() {
bcrypt.DestroyKey(c.kh)
}

func (c *desCipher) BlockSize() int { return desBlockSize }

func (c *desCipher) Encrypt(dst, src []byte) {
Expand Down
12 changes: 10 additions & 2 deletions cng/dsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ type PrivateKeyDSA struct {
hkey bcrypt.KEY_HANDLE
}

func (k *PrivateKeyDSA) finalize() {
bcrypt.DestroyKey(k.hkey)
}

// PublicKeyDSA represents a DSA public key.
type PublicKeyDSA struct {
DSAParameters
Expand All @@ -104,6 +108,10 @@ type PublicKeyDSA struct {
hkey bcrypt.KEY_HANDLE
}

func (k *PublicKeyDSA) finalize() {
bcrypt.DestroyKey(k.hkey)
}

// GenerateKeyDSA generates a new private DSA key using the given parameters.
func GenerateKeyDSA(params DSAParameters) (x, y BigInt, err error) {
h, err := loadDSA()
Expand Down Expand Up @@ -147,7 +155,7 @@ func NewPrivateKeyDSA(params DSAParameters, X, Y BigInt) (*PrivateKeyDSA, error)
return nil, err
}
k := &PrivateKeyDSA{params, X, Y, hkey}
addCleanupKey(k, hkey)
runtime.SetFinalizer(k, (*PrivateKeyDSA).finalize)
return k, nil
}

Expand All @@ -166,7 +174,7 @@ func NewPublicKeyDSA(params DSAParameters, Y BigInt) (*PublicKeyDSA, error) {
return nil, err
}
k := &PublicKeyDSA{params, Y, hkey}
addCleanupKey(k, hkey)
runtime.SetFinalizer(k, (*PublicKeyDSA).finalize)
return k, nil
}

Expand Down
19 changes: 14 additions & 5 deletions cng/ecdh.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,21 @@ type PublicKeyECDH struct {
priv *PrivateKeyECDH
}

func (k *PublicKeyECDH) finalize() {
if k.priv == nil {
bcrypt.DestroyKey(k.hkey)
}
}

type PrivateKeyECDH struct {
hkey bcrypt.KEY_HANDLE
isNIST bool
}

func (k *PrivateKeyECDH) finalize() {
bcrypt.DestroyKey(k.hkey)
}

func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) {
// First establish the shared secret.
var secret bcrypt.SECRET_HANDLE
Expand Down Expand Up @@ -128,7 +138,7 @@ func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) {
bytes = bytes[hdr.KeySize*2:]

k := &PrivateKeyECDH{hkey, isNIST(curve)}
addCleanupKey(k, hkey)
runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize)
return k, bytes, nil
}

Expand Down Expand Up @@ -163,7 +173,7 @@ func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) {
return nil, err
}
k := &PublicKeyECDH{hkey, append([]byte(nil), bytes...), nil}
addCleanupKey(k, hkey)
runtime.SetFinalizer(k, (*PublicKeyECDH).finalize)
return k, nil
}

Expand Down Expand Up @@ -192,7 +202,7 @@ func NewPrivateKeyECDH(curve string, key []byte) (*PrivateKeyECDH, error) {
return nil, err
}
k := &PrivateKeyECDH{hkey, nist}
addCleanupKey(k, hkey)
runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize)
return k, nil
}

Expand All @@ -210,9 +220,8 @@ func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) {
// Only include X.
bytes = data[:hdr.KeySize]
}
// No cleanup needed: pub.priv prevents k from being garbage collected,
// so k's cleanup will destroy the shared hkey when both are unreachable.
pub := &PublicKeyECDH{k.hkey, bytes, k}
runtime.SetFinalizer(pub, (*PublicKeyECDH).finalize)
return pub, nil
}

Expand Down
104 changes: 0 additions & 104 deletions cng/ecdh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,107 +158,3 @@ func hexDecode(t *testing.T, s string) []byte {
}
return b
}

func BenchmarkGenerateKeyECDH(b *testing.B) {
for _, curve := range []string{"P-256", "P-384", "P-521", "X25519"} {
b.Run(curve, func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := cng.GenerateKeyECDH(curve)
if err != nil {
b.Fatal(err)
}
}
})
}
}

func BenchmarkECDH(b *testing.B) {
for _, curve := range []string{"P-256", "P-384", "P-521", "X25519"} {
b.Run(curve, func(b *testing.B) {
aliceKey, _, err := cng.GenerateKeyECDH(curve)
if err != nil {
b.Fatal(err)
}
bobKey, _, err := cng.GenerateKeyECDH(curve)
if err != nil {
b.Fatal(err)
}
bobPub, err := bobKey.PublicKey()
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := cng.ECDH(aliceKey, bobPub)
if err != nil {
b.Fatal(err)
}
}
})
}
}

func BenchmarkNewPrivateKeyECDH(b *testing.B) {
for _, curve := range []string{"P-256", "P-384", "P-521", "X25519"} {
b.Run(curve, func(b *testing.B) {
_, privBytes, err := cng.GenerateKeyECDH(curve)
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := cng.NewPrivateKeyECDH(curve, privBytes)
if err != nil {
b.Fatal(err)
}
}
})
}
}

func BenchmarkNewPublicKeyECDH(b *testing.B) {
for _, curve := range []string{"P-256", "P-384", "P-521", "X25519"} {
b.Run(curve, func(b *testing.B) {
key, _, err := cng.GenerateKeyECDH(curve)
if err != nil {
b.Fatal(err)
}
pub, err := key.PublicKey()
if err != nil {
b.Fatal(err)
}
pubBytes := pub.Bytes()
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := cng.NewPublicKeyECDH(curve, pubBytes)
if err != nil {
b.Fatal(err)
}
}
})
}
}

func BenchmarkPublicKeyECDH(b *testing.B) {
for _, curve := range []string{"P-256", "P-384", "P-521", "X25519"} {
b.Run(curve, func(b *testing.B) {
key, _, err := cng.GenerateKeyECDH(curve)
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := key.PublicKey()
if err != nil {
b.Fatal(err)
}
}
})
}
}
12 changes: 10 additions & 2 deletions cng/ecdsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,14 @@ func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) {
return nil, err
}
k := &PublicKeyECDSA{hkey}
addCleanupKey(k, hkey)
runtime.SetFinalizer(k, (*PublicKeyECDSA).finalize)
return k, nil
}

func (k *PublicKeyECDSA) finalize() {
bcrypt.DestroyKey(k.hkey)
}

type PrivateKeyECDSA struct {
hkey bcrypt.KEY_HANDLE
}
Expand All @@ -108,10 +112,14 @@ func NewPrivateKeyECDSA(curve string, X, Y, D BigInt) (*PrivateKeyECDSA, error)
return nil, err
}
k := &PrivateKeyECDSA{hkey}
addCleanupKey(k, hkey)
runtime.SetFinalizer(k, (*PrivateKeyECDSA).finalize)
return k, nil
}

func (k *PrivateKeyECDSA) finalize() {
bcrypt.DestroyKey(k.hkey)
}

// SignECDSA signs a hash (which should be the result of hashing a larger message),
// using the private key, priv.
//
Expand Down
15 changes: 6 additions & 9 deletions cng/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ import (
// maxHashSize is the size of SHA512 and SHA3_512, the largest hashes we support.
const maxHashSize = 64

// addCleanupHash attaches a cleanup function to ptr that will destroy ctx.
func addCleanupHash[T any](ptr *T, ctx bcrypt.HASH_HANDLE) {
runtime.AddCleanup(ptr, func(ctx bcrypt.HASH_HANDLE) {
bcrypt.DestroyHash(ctx)
}, ctx)
}

// SupportsHash returns true if a hash.Hash implementation is supported for h.
func SupportsHash(h crypto.Hash) bool {
switch h {
Expand Down Expand Up @@ -195,6 +188,10 @@ func newHash(id string) *Hash {
return &Hash{alg: mustLoadHash(id, bcrypt.ALG_NONE_FLAG)}
}

func (h *Hash) finalize() {
bcrypt.DestroyHash(h.ctx)
}

func (h *Hash) init() {
defer runtime.KeepAlive(h)
if h.ctx != 0 {
Expand All @@ -204,15 +201,15 @@ func (h *Hash) init() {
if err != nil {
panic(err)
}
addCleanupHash(h, h.ctx)
runtime.SetFinalizer(h, (*Hash).finalize)
}

func (h *Hash) Clone() (HashCloner, error) {
defer runtime.KeepAlive(h)
h2 := &Hash{alg: h.alg, key: bytes.Clone(h.key)}
if h.ctx != 0 {
hashClone(h.ctx, &h2.ctx)
addCleanupHash(h2, h2.ctx)
runtime.SetFinalizer(h2, (*Hash).finalize)
}
return h2, nil
}
Expand Down
8 changes: 0 additions & 8 deletions cng/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,11 @@ package cng

import (
"errors"
"runtime"
"unsafe"

"github.com/microsoft/go-crypto-winnative/internal/bcrypt"
)

// addCleanupKey attaches a cleanup function to ptr that will destroy kh.
func addCleanupKey[T any](ptr *T, kh bcrypt.KEY_HANDLE) {
runtime.AddCleanup(ptr, func(kh bcrypt.KEY_HANDLE) {
bcrypt.DestroyKey(kh)
}, kh)
}

const (
sizeOfECCBlobHeader = uint32(unsafe.Sizeof(bcrypt.ECCKEY_BLOB{}))
sizeOfRSABlobHeader = uint32(unsafe.Sizeof(bcrypt.RSAKEY_BLOB{}))
Expand Down
Loading
Loading