Source file src/crypto/rsa/boring.go

     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 = new(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 = new(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: new(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:         new(big.Int).Set(k.D),
   115  	}
   116  	dst.Primes = make([]*big.Int, len(k.Primes))
   117  	for i, p := range k.Primes {
   118  		dst.Primes[i] = new(big.Int).Set(p)
   119  	}
   120  	if x := k.Precomputed.Dp; x != nil {
   121  		dst.Precomputed.Dp = new(big.Int).Set(x)
   122  	}
   123  	if x := k.Precomputed.Dq; x != nil {
   124  		dst.Precomputed.Dq = new(big.Int).Set(x)
   125  	}
   126  	if x := k.Precomputed.Qinv; x != nil {
   127  		dst.Precomputed.Qinv = new(big.Int).Set(x)
   128  	}
   129  	return dst
   130  }
   131  

View as plain text