diff options
Diffstat (limited to 'src/crypto/rsa/boring.go')
-rw-r--r-- | src/crypto/rsa/boring.go | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/crypto/rsa/boring.go b/src/crypto/rsa/boring.go new file mode 100644 index 0000000..9b1db56 --- /dev/null +++ b/src/crypto/rsa/boring.go @@ -0,0 +1,131 @@ +// Copyright 2017 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. + +//go:build boringcrypto + +package rsa + +import ( + "crypto/internal/boring" + "crypto/internal/boring/bbig" + "crypto/internal/boring/bcache" + "math/big" + "unsafe" +) + +// Cached conversions from Go PublicKey/PrivateKey to BoringCrypto. +// +// The first operation on a PublicKey or PrivateKey makes a parallel +// BoringCrypto key and saves it in pubCache or privCache. +// +// We could just assume that once used in a sign/verify/encrypt/decrypt operation, +// a particular key is never again modified, but that has not been a +// stated assumption before. Just in case there is any existing code that +// does modify the key between operations, we save the original values +// alongside the cached BoringCrypto key and check that the real key +// still matches before using the cached key. The theory is that the real +// operations are significantly more expensive than the comparison. + +type boringPub struct { + key *boring.PublicKeyRSA + orig PublicKey +} + +var pubCache bcache.Cache +var privCache bcache.Cache + +func init() { + pubCache.Register() + privCache.Register() +} + +func boringPublicKey(pub *PublicKey) (*boring.PublicKeyRSA, error) { + b := (*boringPub)(pubCache.Get(unsafe.Pointer(pub))) + if b != nil && publicKeyEqual(&b.orig, pub) { + return b.key, nil + } + + b = new(boringPub) + b.orig = copyPublicKey(pub) + key, err := boring.NewPublicKeyRSA(bbig.Enc(b.orig.N), bbig.Enc(big.NewInt(int64(b.orig.E)))) + if err != nil { + return nil, err + } + b.key = key + pubCache.Put(unsafe.Pointer(pub), unsafe.Pointer(b)) + return key, nil +} + +type boringPriv struct { + key *boring.PrivateKeyRSA + orig PrivateKey +} + +func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyRSA, error) { + b := (*boringPriv)(privCache.Get(unsafe.Pointer(priv))) + if b != nil && privateKeyEqual(&b.orig, priv) { + return b.key, nil + } + + b = new(boringPriv) + b.orig = copyPrivateKey(priv) + + var N, E, D, P, Q, Dp, Dq, Qinv *big.Int + N = b.orig.N + E = big.NewInt(int64(b.orig.E)) + D = b.orig.D + if len(b.orig.Primes) == 2 { + P = b.orig.Primes[0] + Q = b.orig.Primes[1] + Dp = b.orig.Precomputed.Dp + Dq = b.orig.Precomputed.Dq + Qinv = b.orig.Precomputed.Qinv + } + key, err := boring.NewPrivateKeyRSA(bbig.Enc(N), bbig.Enc(E), bbig.Enc(D), bbig.Enc(P), bbig.Enc(Q), bbig.Enc(Dp), bbig.Enc(Dq), bbig.Enc(Qinv)) + if err != nil { + return nil, err + } + b.key = key + privCache.Put(unsafe.Pointer(priv), unsafe.Pointer(b)) + return key, nil +} + +func publicKeyEqual(k1, k2 *PublicKey) bool { + return k1.N != nil && + k1.N.Cmp(k2.N) == 0 && + k1.E == k2.E +} + +func copyPublicKey(k *PublicKey) PublicKey { + return PublicKey{ + N: new(big.Int).Set(k.N), + E: k.E, + } +} + +func privateKeyEqual(k1, k2 *PrivateKey) bool { + return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) && + k1.D.Cmp(k2.D) == 0 +} + +func copyPrivateKey(k *PrivateKey) PrivateKey { + dst := PrivateKey{ + PublicKey: copyPublicKey(&k.PublicKey), + D: new(big.Int).Set(k.D), + } + dst.Primes = make([]*big.Int, len(k.Primes)) + for i, p := range k.Primes { + dst.Primes[i] = new(big.Int).Set(p) + } + if x := k.Precomputed.Dp; x != nil { + dst.Precomputed.Dp = new(big.Int).Set(x) + } + if x := k.Precomputed.Dq; x != nil { + dst.Precomputed.Dq = new(big.Int).Set(x) + } + if x := k.Precomputed.Qinv; x != nil { + dst.Precomputed.Qinv = new(big.Int).Set(x) + } + return dst +} |