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 7package ecdsa 8 9import ( 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 29var pubCache bcache.Cache[PublicKey, boringPub] 30var privCache bcache.Cache[PrivateKey, boringPriv] 31 32func init() { 33 pubCache.Register() 34 privCache.Register() 35} 36 37type boringPub struct { 38 key *boring.PublicKeyECDSA 39 orig PublicKey 40} 41 42func 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 = new(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 59type boringPriv struct { 60 key *boring.PrivateKeyECDSA 61 orig PrivateKey 62} 63 64func 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 = new(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 81func 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 88func privateKeyEqual(k1, k2 *PrivateKey) bool { 89 return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) && 90 k1.D.Cmp(k2.D) == 0 91} 92 93func copyPublicKey(k *PublicKey) PublicKey { 94 return PublicKey{ 95 Curve: k.Curve, 96 X: new(big.Int).Set(k.X), 97 Y: new(big.Int).Set(k.Y), 98 } 99} 100 101func copyPrivateKey(k *PrivateKey) PrivateKey { 102 return PrivateKey{ 103 PublicKey: copyPublicKey(&k.PublicKey), 104 D: new(big.Int).Set(k.D), 105 } 106} 107