boring.mx raw

   1  // Copyright 2017 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build boringcrypto
   6  
   7  package rsa
   8  
   9  import (
  10  	"crypto/internal/boring"
  11  	"crypto/internal/boring/bbig"
  12  	"crypto/internal/boring/bcache"
  13  	"math/big"
  14  )
  15  
  16  // Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
  17  //
  18  // The first operation on a PublicKey or PrivateKey makes a parallel
  19  // BoringCrypto key and saves it in pubCache or privCache.
  20  //
  21  // We could just assume that once used in a sign/verify/encrypt/decrypt operation,
  22  // a particular key is never again modified, but that has not been a
  23  // stated assumption before. Just in case there is any existing code that
  24  // does modify the key between operations, we save the original values
  25  // alongside the cached BoringCrypto key and check that the real key
  26  // still matches before using the cached key. The theory is that the real
  27  // operations are significantly more expensive than the comparison.
  28  
  29  type boringPub struct {
  30  	key  *boring.PublicKeyRSA
  31  	orig PublicKey
  32  }
  33  
  34  var pubCache bcache.Cache[PublicKey, boringPub]
  35  var privCache bcache.Cache[PrivateKey, boringPriv]
  36  
  37  func init() {
  38  	pubCache.Register()
  39  	privCache.Register()
  40  }
  41  
  42  func boringPublicKey(pub *PublicKey) (*boring.PublicKeyRSA, error) {
  43  	b := pubCache.Get(pub)
  44  	if b != nil && publicKeyEqual(&b.orig, pub) {
  45  		return b.key, nil
  46  	}
  47  
  48  	b = &boringPub{}
  49  	b.orig = copyPublicKey(pub)
  50  	key, err := boring.NewPublicKeyRSA(bbig.Enc(b.orig.N), bbig.Enc(big.NewInt(int64(b.orig.E))))
  51  	if err != nil {
  52  		return nil, err
  53  	}
  54  	b.key = key
  55  	pubCache.Put(pub, b)
  56  	return key, nil
  57  }
  58  
  59  type boringPriv struct {
  60  	key  *boring.PrivateKeyRSA
  61  	orig PrivateKey
  62  }
  63  
  64  func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyRSA, error) {
  65  	b := privCache.Get(priv)
  66  	if b != nil && privateKeyEqual(&b.orig, priv) {
  67  		return b.key, nil
  68  	}
  69  
  70  	b = &boringPriv{}
  71  	b.orig = copyPrivateKey(priv)
  72  
  73  	var N, E, D, P, Q, Dp, Dq, Qinv *big.Int
  74  	N = b.orig.N
  75  	E = big.NewInt(int64(b.orig.E))
  76  	D = b.orig.D
  77  	if len(b.orig.Primes) == 2 {
  78  		P = b.orig.Primes[0]
  79  		Q = b.orig.Primes[1]
  80  		Dp = b.orig.Precomputed.Dp
  81  		Dq = b.orig.Precomputed.Dq
  82  		Qinv = b.orig.Precomputed.Qinv
  83  	}
  84  	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))
  85  	if err != nil {
  86  		return nil, err
  87  	}
  88  	b.key = key
  89  	privCache.Put(priv, b)
  90  	return key, nil
  91  }
  92  
  93  func publicKeyEqual(k1, k2 *PublicKey) bool {
  94  	return k1.N != nil &&
  95  		k1.N.Cmp(k2.N) == 0 &&
  96  		k1.E == k2.E
  97  }
  98  
  99  func copyPublicKey(k *PublicKey) PublicKey {
 100  	return PublicKey{
 101  		N: (&big.Int{}).Set(k.N),
 102  		E: k.E,
 103  	}
 104  }
 105  
 106  func privateKeyEqual(k1, k2 *PrivateKey) bool {
 107  	return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
 108  		k1.D.Cmp(k2.D) == 0
 109  }
 110  
 111  func copyPrivateKey(k *PrivateKey) PrivateKey {
 112  	dst := PrivateKey{
 113  		PublicKey: copyPublicKey(&k.PublicKey),
 114  		D:         (&big.Int{}).Set(k.D),
 115  	}
 116  	dst.Primes = []*big.Int{:len(k.Primes)}
 117  	for i, p := range k.Primes {
 118  		dst.Primes[i] = (&big.Int{}).Set(p)
 119  	}
 120  	if x := k.Precomputed.Dp; x != nil {
 121  		dst.Precomputed.Dp = (&big.Int{}).Set(x)
 122  	}
 123  	if x := k.Precomputed.Dq; x != nil {
 124  		dst.Precomputed.Dq = (&big.Int{}).Set(x)
 125  	}
 126  	if x := k.Precomputed.Qinv; x != nil {
 127  		dst.Precomputed.Qinv = (&big.Int{}).Set(x)
 128  	}
 129  	return dst
 130  }
 131