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 rsa 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/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 29type boringPub struct { 30 key *boring.PublicKeyRSA 31 orig PublicKey 32} 33 34var pubCache bcache.Cache[PublicKey, boringPub] 35var privCache bcache.Cache[PrivateKey, boringPriv] 36 37func init() { 38 pubCache.Register() 39 privCache.Register() 40} 41 42func 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 59type boringPriv struct { 60 key *boring.PrivateKeyRSA 61 orig PrivateKey 62} 63 64func 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 93func publicKeyEqual(k1, k2 *PublicKey) bool { 94 return k1.N != nil && 95 k1.N.Cmp(k2.N) == 0 && 96 k1.E == k2.E 97} 98 99func copyPublicKey(k *PublicKey) PublicKey { 100 return PublicKey{ 101 N: new(big.Int).Set(k.N), 102 E: k.E, 103 } 104} 105 106func privateKeyEqual(k1, k2 *PrivateKey) bool { 107 return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) && 108 k1.D.Cmp(k2.D) == 0 109} 110 111func 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