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 ecdsa
   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 or Verify 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  var pubCache bcache.Cache[PublicKey, boringPub]
  30  var privCache bcache.Cache[PrivateKey, boringPriv]
  31  
  32  func init() {
  33  	pubCache.Register()
  34  	privCache.Register()
  35  }
  36  
  37  type boringPub struct {
  38  	key  *boring.PublicKeyECDSA
  39  	orig PublicKey
  40  }
  41  
  42  func boringPublicKey(pub *PublicKey) (*boring.PublicKeyECDSA, 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.NewPublicKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y))
  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.PrivateKeyECDSA
  61  	orig PrivateKey
  62  }
  63  
  64  func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyECDSA, 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  	key, err := boring.NewPrivateKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y), bbig.Enc(b.orig.D))
  73  	if err != nil {
  74  		return nil, err
  75  	}
  76  	b.key = key
  77  	privCache.Put(priv, b)
  78  	return key, nil
  79  }
  80  
  81  func publicKeyEqual(k1, k2 *PublicKey) bool {
  82  	return k1.X != nil &&
  83  		k1.Curve.Params() == k2.Curve.Params() &&
  84  		k1.X.Cmp(k2.X) == 0 &&
  85  		k1.Y.Cmp(k2.Y) == 0
  86  }
  87  
  88  func privateKeyEqual(k1, k2 *PrivateKey) bool {
  89  	return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
  90  		k1.D.Cmp(k2.D) == 0
  91  }
  92  
  93  func copyPublicKey(k *PublicKey) PublicKey {
  94  	return PublicKey{
  95  		Curve: k.Curve,
  96  		X:     (&big.Int{}).Set(k.X),
  97  		Y:     (&big.Int{}).Set(k.Y),
  98  	}
  99  }
 100  
 101  func copyPrivateKey(k *PrivateKey) PrivateKey {
 102  	return PrivateKey{
 103  		PublicKey: copyPublicKey(&k.PublicKey),
 104  		D:         (&big.Int{}).Set(k.D),
 105  	}
 106  }
 107