V2 also has issues, as flagged by patchtest and my local testing: Applying: go: Backport fix for CVE-2023-45287 error: corrupt patch at line 2273 error: could not build fake ancestor Patch failed at 0001 go: Backport fix for CVE-2023-45287
Steve On Thu, Jan 4, 2024 at 9:33 PM Vijay Anusuri via lists.openembedded.org <vanusuri=mvista....@lists.openembedded.org> wrote: > > From: Vijay Anusuri <vanus...@mvista.com> > > Upstream-Status: Backport > [https://github.com/golang/go/commit/9baafabac9a84813a336f068862207d2bb06d255 > & > https://github.com/golang/go/commit/c9d5f60eaa4450ccf1ce878d55b4c6a12843f2f3 > & > https://github.com/golang/go/commit/8f676144ad7b7c91adb0c6e1ec89aaa6283c6807 > & > https://github.com/golang/go/commit/8a81fdf165facdcefa06531de5af98a4db343035] > > Signed-off-by: Vijay Anusuri <vanus...@mvista.com> > --- > meta/recipes-devtools/go/go-1.14.inc | 4 + > .../go/go-1.14/CVE-2023-45287-pre1.patch | 393 ++++ > .../go/go-1.14/CVE-2023-45287-pre2.patch | 401 ++++ > .../go/go-1.14/CVE-2023-45287-pre3.patch | 86 + > .../go/go-1.14/CVE-2023-45287.patch | 1697 +++++++++++++++++ > 5 files changed, 2581 insertions(+) > create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre1.patch > create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre2.patch > create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre3.patch > create mode 100644 meta/recipes-devtools/go/go-1.14/CVE-2023-45287.patch > > diff --git a/meta/recipes-devtools/go/go-1.14.inc > b/meta/recipes-devtools/go/go-1.14.inc > index b827a3606d..42a9ac8435 100644 > --- a/meta/recipes-devtools/go/go-1.14.inc > +++ b/meta/recipes-devtools/go/go-1.14.inc > @@ -83,6 +83,10 @@ SRC_URI += "\ > file://CVE-2023-39318.patch \ > file://CVE-2023-39319.patch \ > file://CVE-2023-39326.patch \ > + file://CVE-2023-45287-pre1.patch \ > + file://CVE-2023-45287-pre2.patch \ > + file://CVE-2023-45287-pre3.patch \ > + file://CVE-2023-45287.patch \ > " > > SRC_URI_append_libc-musl = " > file://0009-ld-replace-glibc-dynamic-linker-with-musl.patch" > diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre1.patch > b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre1.patch > new file mode 100644 > index 0000000000..4d65180253 > --- /dev/null > +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre1.patch > @@ -0,0 +1,393 @@ > +From 9baafabac9a84813a336f068862207d2bb06d255 Mon Sep 17 00:00:00 2001 > +From: Filippo Valsorda <fili...@golang.org> > +Date: Wed, 1 Apr 2020 17:25:40 -0400 > +Subject: [PATCH] crypto/rsa: refactor RSA-PSS signing and verification > + > +Cleaned up for readability and consistency. > + > +There is one tiny behavioral change: when PSSSaltLengthEqualsHash is > +used and both hash and opts.Hash were set, hash.Size() was used for the > +salt length instead of opts.Hash.Size(). That's clearly wrong because > +opts.Hash is documented to override hash. > + > +Change-Id: I3e25dad933961eac827c6d2e3bbfe45fc5a6fb0e > +Reviewed-on: https://go-review.googlesource.com/c/go/+/226937 > +Run-TryBot: Filippo Valsorda <fili...@golang.org> > +TryBot-Result: Gobot Gobot <go...@golang.org> > +Reviewed-by: Katie Hockman <ka...@golang.org> > + > +Upstream-Status: Backport > [https://github.com/golang/go/commit/9baafabac9a84813a336f068862207d2bb06d255] > +CVE: CVE-2023-45287 #Dependency Patch1 > +Signed-off-by: Vijay Anusuri <vanus...@mvista.com> > +--- > + src/crypto/rsa/pss.go | 173 ++++++++++++++++++++++-------------------- > + src/crypto/rsa/rsa.go | 9 ++- > + 2 files changed, 96 insertions(+), 86 deletions(-) > + > +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go > +index 3ff0c2f4d0076..f9844d87329a8 100644 > +--- a/src/crypto/rsa/pss.go > ++++ b/src/crypto/rsa/pss.go > +@@ -4,9 +4,7 @@ > + > + package rsa > + > +-// This file implements the PSS signature scheme [1]. > +-// > +-// [1] > https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf > ++// This file implements the RSASSA-PSS signature scheme according to RFC > 8017. > + > + import ( > + "bytes" > +@@ -17,8 +15,22 @@ import ( > + "math/big" > + ) > + > ++// Per RFC 8017, Section 9.1 > ++// > ++// EM = MGF1 xor DB || H( 8*0x00 || mHash || salt ) || 0xbc > ++// > ++// where > ++// > ++// DB = PS || 0x01 || salt > ++// > ++// and PS can be empty so > ++// > ++// emLen = dbLen + hLen + 1 = psLen + sLen + hLen + 2 > ++// > ++ > + func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) > ([]byte, error) { > +- // See [1], section 9.1.1 > ++ // See RFC 8017, Section 9.1.1. > ++ > + hLen := hash.Size() > + sLen := len(salt) > + emLen := (emBits + 7) / 8 > +@@ -30,7 +42,7 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, > hash hash.Hash) ([]byt > + // 2. Let mHash = Hash(M), an octet string of length hLen. > + > + if len(mHash) != hLen { > +- return nil, errors.New("crypto/rsa: input must be hashed > message") > ++ return nil, errors.New("crypto/rsa: input must be hashed with > given hash") > + } > + > + // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. > +@@ -40,8 +52,9 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, > hash hash.Hash) ([]byt > + } > + > + em := make([]byte, emLen) > +- db := em[:emLen-sLen-hLen-2+1+sLen] > +- h := em[emLen-sLen-hLen-2+1+sLen : emLen-1] > ++ psLen := emLen - sLen - hLen - 2 > ++ db := em[:psLen+1+sLen] > ++ h := em[psLen+1+sLen : emLen-1] > + > + // 4. Generate a random octet string salt of length sLen; if sLen = > 0, > + // then salt is the empty string. > +@@ -69,8 +82,8 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, > hash hash.Hash) ([]byt > + // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length > + // emLen - hLen - 1. > + > +- db[emLen-sLen-hLen-2] = 0x01 > +- copy(db[emLen-sLen-hLen-1:], salt) > ++ db[psLen] = 0x01 > ++ copy(db[psLen+1:], salt) > + > + // 9. Let dbMask = MGF(H, emLen - hLen - 1). > + // > +@@ -81,47 +94,57 @@ func emsaPSSEncode(mHash []byte, emBits int, salt > []byte, hash hash.Hash) ([]byt > + // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet > in > + // maskedDB to zero. > + > +- db[0] &= (0xFF >> uint(8*emLen-emBits)) > ++ db[0] &= 0xff >> (8*emLen - emBits) > + > + // 12. Let EM = maskedDB || H || 0xbc. > +- em[emLen-1] = 0xBC > ++ em[emLen-1] = 0xbc > + > + // 13. Output EM. > + return em, nil > + } > + > + func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) > error { > ++ // See RFC 8017, Section 9.1.2. > ++ > ++ hLen := hash.Size() > ++ if sLen == PSSSaltLengthEqualsHash { > ++ sLen = hLen > ++ } > ++ emLen := (emBits + 7) / 8 > ++ if emLen != len(em) { > ++ return errors.New("rsa: internal error: inconsistent length") > ++ } > ++ > + // 1. If the length of M is greater than the input limitation for the > + // hash function (2^61 - 1 octets for SHA-1), output > "inconsistent" > + // and stop. > + // > + // 2. Let mHash = Hash(M), an octet string of length hLen. > +- hLen := hash.Size() > + if hLen != len(mHash) { > + return ErrVerification > + } > + > + // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. > +- emLen := (emBits + 7) / 8 > + if emLen < hLen+sLen+2 { > + return ErrVerification > + } > + > + // 4. If the rightmost octet of EM does not have hexadecimal value > + // 0xbc, output "inconsistent" and stop. > +- if em[len(em)-1] != 0xBC { > ++ if em[emLen-1] != 0xbc { > + return ErrVerification > + } > + > + // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and > + // let H be the next hLen octets. > + db := em[:emLen-hLen-1] > +- h := em[emLen-hLen-1 : len(em)-1] > ++ h := em[emLen-hLen-1 : emLen-1] > + > + // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet > in > + // maskedDB are not all equal to zero, output "inconsistent" and > + // stop. > +- if em[0]&(0xFF<<uint(8-(8*emLen-emBits))) != 0 { > ++ var bitMask byte = 0xff >> (8*emLen - emBits) > ++ if em[0] & ^bitMask != 0 { > + return ErrVerification > + } > + > +@@ -132,37 +155,30 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, > hash hash.Hash) error { > + > + // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet > in DB > + // to zero. > +- db[0] &= (0xFF >> uint(8*emLen-emBits)) > ++ db[0] &= bitMask > + > ++ // If we don't know the salt length, look for the 0x01 delimiter. > + if sLen == PSSSaltLengthAuto { > +- FindSaltLength: > +- for sLen = emLen - (hLen + 2); sLen >= 0; sLen-- { > +- switch db[emLen-hLen-sLen-2] { > +- case 1: > +- break FindSaltLength > +- case 0: > +- continue > +- default: > +- return ErrVerification > +- } > +- } > +- if sLen < 0 { > ++ psLen := bytes.IndexByte(db, 0x01) > ++ if psLen < 0 { > + return ErrVerification > + } > +- } else { > +- // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB > are not zero > +- // or if the octet at position emLen - hLen - sLen - 1 > (the leftmost > +- // position is "position 1") does not have hexadecimal > value 0x01, > +- // output "inconsistent" and stop. > +- for _, e := range db[:emLen-hLen-sLen-2] { > +- if e != 0x00 { > +- return ErrVerification > +- } > +- } > +- if db[emLen-hLen-sLen-2] != 0x01 { > ++ sLen = len(db) - psLen - 1 > ++ } > ++ > ++ // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not > zero > ++ // or if the octet at position emLen - hLen - sLen - 1 (the > leftmost > ++ // position is "position 1") does not have hexadecimal value 0x01, > ++ // output "inconsistent" and stop. > ++ psLen := emLen - hLen - sLen - 2 > ++ for _, e := range db[:psLen] { > ++ if e != 0x00 { > + return ErrVerification > + } > + } > ++ if db[psLen] != 0x01 { > ++ return ErrVerification > ++ } > + > + // 11. Let salt be the last sLen octets of DB. > + salt := db[len(db)-sLen:] > +@@ -181,19 +197,19 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, > hash hash.Hash) error { > + h0 := hash.Sum(nil) > + > + // 14. If H = H', output "consistent." Otherwise, output > "inconsistent." > +- if !bytes.Equal(h0, h) { > ++ if !bytes.Equal(h0, h) { // TODO: constant time? > + return ErrVerification > + } > + return nil > + } > + > +-// signPSSWithSalt calculates the signature of hashed using PSS [1] with > specified salt. > ++// signPSSWithSalt calculates the signature of hashed using PSS with > specified salt. > + // Note that hashed must be the result of hashing the input message using > the > + // given hash function. salt is a random sequence of bytes whose length > will be > + // later used to verify the signature. > + func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, > hashed, salt []byte) (s []byte, err error) { > +- nBits := priv.N.BitLen() > +- em, err := emsaPSSEncode(hashed, nBits-1, salt, hash.New()) > ++ emBits := priv.N.BitLen() - 1 > ++ em, err := emsaPSSEncode(hashed, emBits, salt, hash.New()) > + if err != nil { > + return > + } > +@@ -202,7 +218,7 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, > hash crypto.Hash, hashed, > + if err != nil { > + return > + } > +- s = make([]byte, (nBits+7)/8) > ++ s = make([]byte, priv.Size()) > + copyWithLeftPad(s, c.Bytes()) > + return > + } > +@@ -223,16 +239,15 @@ type PSSOptions struct { > + // PSSSaltLength constants. > + SaltLength int > + > +- // Hash, if not zero, overrides the hash function passed to SignPSS. > +- // This is the only way to specify the hash function when using the > +- // crypto.Signer interface. > ++ // Hash is the hash function used to generate the message digest. If > not > ++ // zero, it overrides the hash function passed to SignPSS. It's > required > ++ // when using PrivateKey.Sign. > + Hash crypto.Hash > + } > + > +-// HashFunc returns pssOpts.Hash so that PSSOptions implements > +-// crypto.SignerOpts. > +-func (pssOpts *PSSOptions) HashFunc() crypto.Hash { > +- return pssOpts.Hash > ++// HashFunc returns opts.Hash so that PSSOptions implements > crypto.SignerOpts. > ++func (opts *PSSOptions) HashFunc() crypto.Hash { > ++ return opts.Hash > + } > + > + func (opts *PSSOptions) saltLength() int { > +@@ -242,56 +257,50 @@ func (opts *PSSOptions) saltLength() int { > + return opts.SaltLength > + } > + > +-// SignPSS calculates the signature of hashed using RSASSA-PSS [1]. > +-// Note that hashed must be the result of hashing the input message using > the > +-// given hash function. The opts argument may be nil, in which case sensible > +-// defaults are used. > +-func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed > []byte, opts *PSSOptions) ([]byte, error) { > ++// SignPSS calculates the signature of digest using PSS. > ++// > ++// digest must be the result of hashing the input message using the given > hash > ++// function. The opts argument may be nil, in which case sensible defaults > are > ++// used. If opts.Hash is set, it overrides hash. > ++func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest > []byte, opts *PSSOptions) ([]byte, error) { > ++ if opts != nil && opts.Hash != 0 { > ++ hash = opts.Hash > ++ } > ++ > + saltLength := opts.saltLength() > + switch saltLength { > + case PSSSaltLengthAuto: > +- saltLength = (priv.N.BitLen()+7)/8 - 2 - hash.Size() > ++ saltLength = priv.Size() - 2 - hash.Size() > + case PSSSaltLengthEqualsHash: > + saltLength = hash.Size() > + } > + > +- if opts != nil && opts.Hash != 0 { > +- hash = opts.Hash > +- } > +- > + salt := make([]byte, saltLength) > + if _, err := io.ReadFull(rand, salt); err != nil { > + return nil, err > + } > +- return signPSSWithSalt(rand, priv, hash, hashed, salt) > ++ return signPSSWithSalt(rand, priv, hash, digest, salt) > + } > + > + // VerifyPSS verifies a PSS signature. > +-// hashed is the result of hashing the input message using the given hash > +-// function and sig is the signature. A valid signature is indicated by > +-// returning a nil error. The opts argument may be nil, in which case > sensible > +-// defaults are used. > +-func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, > opts *PSSOptions) error { > +- return verifyPSS(pub, hash, hashed, sig, opts.saltLength()) > +-} > +- > +-// verifyPSS verifies a PSS signature with the given salt length. > +-func verifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, > saltLen int) error { > +- nBits := pub.N.BitLen() > +- if len(sig) != (nBits+7)/8 { > ++// > ++// A valid signature is indicated by returning a nil error. digest must be > the > ++// result of hashing the input message using the given hash function. The > opts > ++// argument may be nil, in which case sensible defaults are used. opts.Hash > is > ++// ignored. > ++func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, > opts *PSSOptions) error { > ++ if len(sig) != pub.Size() { > + return ErrVerification > + } > + s := new(big.Int).SetBytes(sig) > + m := encrypt(new(big.Int), pub, s) > +- emBits := nBits - 1 > ++ emBits := pub.N.BitLen() - 1 > + emLen := (emBits + 7) / 8 > +- if emLen < len(m.Bytes()) { > ++ emBytes := m.Bytes() > ++ if emLen < len(emBytes) { > + return ErrVerification > + } > + em := make([]byte, emLen) > +- copyWithLeftPad(em, m.Bytes()) > +- if saltLen == PSSSaltLengthEqualsHash { > +- saltLen = hash.Size() > +- } > +- return emsaPSSVerify(hashed, em, emBits, saltLen, hash.New()) > ++ copyWithLeftPad(em, emBytes) > ++ return emsaPSSVerify(digest, em, emBits, opts.saltLength(), > hash.New()) > + } > +diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go > +index 5a42990640164..b4bfa13defbdf 100644 > +--- a/src/crypto/rsa/rsa.go > ++++ b/src/crypto/rsa/rsa.go > +@@ -2,7 +2,7 @@ > + // Use of this source code is governed by a BSD-style > + // license that can be found in the LICENSE file. > + > +-// Package rsa implements RSA encryption as specified in PKCS#1. > ++// Package rsa implements RSA encryption as specified in PKCS#1 and RFC > 8017. > + // > + // RSA is a single, fundamental operation that is used in this package to > + // implement either public-key encryption or public-key signatures. > +@@ -10,13 +10,13 @@ > + // The original specification for encryption and signatures with RSA is > PKCS#1 > + // and the terms "RSA encryption" and "RSA signatures" by default refer to > + // PKCS#1 version 1.5. However, that specification has flaws and new designs > +-// should use version two, usually called by just OAEP and PSS, where > ++// should use version 2, usually called by just OAEP and PSS, where > + // possible. > + // > + // Two sets of interfaces are included in this package. When a more abstract > + // interface isn't necessary, there are functions for encrypting/decrypting > + // with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to > abstract > +-// over the public-key primitive, the PrivateKey struct implements the > ++// over the public key primitive, the PrivateKey type implements the > + // Decrypter and Signer interfaces from the crypto package. > + // > + // The RSA operations in this package are not implemented using > constant-time algorithms. > +@@ -111,7 +111,8 @@ func (priv *PrivateKey) Public() crypto.PublicKey { > + > + // Sign signs digest with priv, reading randomness from rand. If opts is a > + // *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 > will > +-// be used. > ++// be used. digest must be the result of hashing the input message using > ++// opts.HashFunc(). > + // > + // This method implements crypto.Signer, which is an interface to support > keys > + // where the private part is kept in, for example, a hardware module. Common > diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre2.patch > b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre2.patch > new file mode 100644 > index 0000000000..1327b44545 > --- /dev/null > +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre2.patch > @@ -0,0 +1,401 @@ > +From c9d5f60eaa4450ccf1ce878d55b4c6a12843f2f3 Mon Sep 17 00:00:00 2001 > +From: Filippo Valsorda <fili...@golang.org> > +Date: Mon, 27 Apr 2020 21:52:38 -0400 > +Subject: [PATCH] math/big: add (*Int).FillBytes > + > +Replaced almost every use of Bytes with FillBytes. > + > +Note that the approved proposal was for > + > + func (*Int) FillBytes(buf []byte) > + > +while this implements > + > + func (*Int) FillBytes(buf []byte) []byte > + > +because the latter was far nicer to use in all callsites. > + > +Fixes #35833 > + > +Change-Id: Ia912df123e5d79b763845312ea3d9a8051343c0a > +Reviewed-on: https://go-review.googlesource.com/c/go/+/230397 > +Reviewed-by: Robert Griesemer <g...@golang.org> > + > +Upstream-Status: Backport > [https://github.com/golang/go/commit/c9d5f60eaa4450ccf1ce878d55b4c6a12843f2f3] > +CVE: CVE-2023-45287 #Dependency Patch2 > +Signed-off-by: Vijay Anusuri <vanus...@mvista.com> > +--- > + src/crypto/elliptic/elliptic.go | 13 ++++---- > + src/crypto/rsa/pkcs1v15.go | 20 +++--------- > + src/crypto/rsa/pss.go | 17 +++++------ > + src/crypto/rsa/rsa.go | 32 +++---------------- > + src/crypto/tls/key_schedule.go | 7 ++--- > + src/crypto/x509/sec1.go | 7 ++--- > + src/math/big/int.go | 15 +++++++++ > + src/math/big/int_test.go | 54 +++++++++++++++++++++++++++++++++ > + src/math/big/nat.go | 15 ++++++--- > + 9 files changed, 106 insertions(+), 74 deletions(-) > + > +diff --git a/src/crypto/elliptic/elliptic.go > b/src/crypto/elliptic/elliptic.go > +index e2f71cdb63bab..bd5168c5fd842 100644 > +--- a/src/crypto/elliptic/elliptic.go > ++++ b/src/crypto/elliptic/elliptic.go > +@@ -277,7 +277,7 @@ var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, > 0x7f} > + func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, > err error) { > + N := curve.Params().N > + bitSize := N.BitLen() > +- byteLen := (bitSize + 7) >> 3 > ++ byteLen := (bitSize + 7) / 8 > + priv = make([]byte, byteLen) > + > + for x == nil { > +@@ -304,15 +304,14 @@ func GenerateKey(curve Curve, rand io.Reader) (priv > []byte, x, y *big.Int, err e > + > + // Marshal converts a point into the uncompressed form specified in section > 4.3.6 of ANSI X9.62. > + func Marshal(curve Curve, x, y *big.Int) []byte { > +- byteLen := (curve.Params().BitSize + 7) >> 3 > ++ byteLen := (curve.Params().BitSize + 7) / 8 > + > + ret := make([]byte, 1+2*byteLen) > + ret[0] = 4 // uncompressed point > + > +- xBytes := x.Bytes() > +- copy(ret[1+byteLen-len(xBytes):], xBytes) > +- yBytes := y.Bytes() > +- copy(ret[1+2*byteLen-len(yBytes):], yBytes) > ++ x.FillBytes(ret[1 : 1+byteLen]) > ++ y.FillBytes(ret[1+byteLen : 1+2*byteLen]) > ++ > + return ret > + } > + > +@@ -320,7 +319,7 @@ func Marshal(curve Curve, x, y *big.Int) []byte { > + // It is an error if the point is not in uncompressed form or is not on the > curve. > + // On error, x = nil. > + func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { > +- byteLen := (curve.Params().BitSize + 7) >> 3 > ++ byteLen := (curve.Params().BitSize + 7) / 8 > + if len(data) != 1+2*byteLen { > + return > + } > +diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go > +index 499242ffc5b57..3208119ae1ff4 100644 > +--- a/src/crypto/rsa/pkcs1v15.go > ++++ b/src/crypto/rsa/pkcs1v15.go > +@@ -61,8 +61,7 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg > []byte) ([]byte, error) > + m := new(big.Int).SetBytes(em) > + c := encrypt(new(big.Int), pub, m) > + > +- copyWithLeftPad(em, c.Bytes()) > +- return em, nil > ++ return c.FillBytes(em), nil > + } > + > + // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme > from PKCS#1 v1.5. > +@@ -150,7 +149,7 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, > ciphertext []byte) (valid > + return > + } > + > +- em = leftPad(m.Bytes(), k) > ++ em = m.FillBytes(make([]byte, k)) > + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) > + secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2) > + > +@@ -256,8 +255,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash > crypto.Hash, hashed []b > + return nil, err > + } > + > +- copyWithLeftPad(em, c.Bytes()) > +- return em, nil > ++ return c.FillBytes(em), nil > + } > + > + // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature. > +@@ -286,7 +284,7 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, > hashed []byte, sig []byte) > + > + c := new(big.Int).SetBytes(sig) > + m := encrypt(new(big.Int), pub, c) > +- em := leftPad(m.Bytes(), k) > ++ em := m.FillBytes(make([]byte, k)) > + // EM = 0x00 || 0x01 || PS || 0x00 || T > + > + ok := subtle.ConstantTimeByteEq(em[0], 0) > +@@ -323,13 +321,3 @@ func pkcs1v15HashInfo(hash crypto.Hash, inLen int) > (hashLen int, prefix []byte, > + } > + return > + } > +- > +-// copyWithLeftPad copies src to the end of dest, padding with zero bytes as > +-// needed. > +-func copyWithLeftPad(dest, src []byte) { > +- numPaddingBytes := len(dest) - len(src) > +- for i := 0; i < numPaddingBytes; i++ { > +- dest[i] = 0 > +- } > +- copy(dest[numPaddingBytes:], src) > +-} > +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go > +index f9844d87329a8..b2adbedb28fa8 100644 > +--- a/src/crypto/rsa/pss.go > ++++ b/src/crypto/rsa/pss.go > +@@ -207,20 +207,19 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, > hash hash.Hash) error { > + // Note that hashed must be the result of hashing the input message using > the > + // given hash function. salt is a random sequence of bytes whose length > will be > + // later used to verify the signature. > +-func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, > hashed, salt []byte) (s []byte, err error) { > ++func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, > hashed, salt []byte) ([]byte, error) { > + emBits := priv.N.BitLen() - 1 > + em, err := emsaPSSEncode(hashed, emBits, salt, hash.New()) > + if err != nil { > +- return > ++ return nil, err > + } > + m := new(big.Int).SetBytes(em) > + c, err := decryptAndCheck(rand, priv, m) > + if err != nil { > +- return > ++ return nil, err > + } > +- s = make([]byte, priv.Size()) > +- copyWithLeftPad(s, c.Bytes()) > +- return > ++ s := make([]byte, priv.Size()) > ++ return c.FillBytes(s), nil > + } > + > + const ( > +@@ -296,11 +295,9 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest > []byte, sig []byte, opts > + m := encrypt(new(big.Int), pub, s) > + emBits := pub.N.BitLen() - 1 > + emLen := (emBits + 7) / 8 > +- emBytes := m.Bytes() > +- if emLen < len(emBytes) { > ++ if m.BitLen() > emLen*8 { > + return ErrVerification > + } > +- em := make([]byte, emLen) > +- copyWithLeftPad(em, emBytes) > ++ em := m.FillBytes(make([]byte, emLen)) > + return emsaPSSVerify(digest, em, emBits, opts.saltLength(), > hash.New()) > + } > +diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go > +index b4bfa13defbdf..28eb5926c1a54 100644 > +--- a/src/crypto/rsa/rsa.go > ++++ b/src/crypto/rsa/rsa.go > +@@ -416,16 +416,9 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub > *PublicKey, msg []byte, l > + m := new(big.Int) > + m.SetBytes(em) > + c := encrypt(new(big.Int), pub, m) > +- out := c.Bytes() > + > +- if len(out) < k { > +- // If the output is too small, we need to left-pad with zeros. > +- t := make([]byte, k) > +- copy(t[k-len(out):], out) > +- out = t > +- } > +- > +- return out, nil > ++ out := make([]byte, k) > ++ return c.FillBytes(out), nil > + } > + > + // ErrDecryption represents a failure to decrypt a message. > +@@ -597,12 +590,9 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv > *PrivateKey, ciphertext > + lHash := hash.Sum(nil) > + hash.Reset() > + > +- // Converting the plaintext number to bytes will strip any > +- // leading zeros so we may have to left pad. We do this > unconditionally > +- // to avoid leaking timing information. (Although we still probably > +- // leak the number of leading zeros. It's not clear that we can do > +- // anything about this.) > +- em := leftPad(m.Bytes(), k) > ++ // We probably leak the number of leading zeros. > ++ // It's not clear that we can do anything about this. > ++ em := m.FillBytes(make([]byte, k)) > + > + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) > + > +@@ -643,15 +633,3 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv > *PrivateKey, ciphertext > + > + return rest[index+1:], nil > + } > +- > +-// leftPad returns a new slice of length size. The contents of input are > right > +-// aligned in the new slice. > +-func leftPad(input []byte, size int) (out []byte) { > +- n := len(input) > +- if n > size { > +- n = size > +- } > +- out = make([]byte, size) > +- copy(out[len(out)-n:], input) > +- return > +-} > +diff --git a/src/crypto/tls/key_schedule.go b/src/crypto/tls/key_schedule.go > +index 2aab323202f7d..314016979afb8 100644 > +--- a/src/crypto/tls/key_schedule.go > ++++ b/src/crypto/tls/key_schedule.go > +@@ -173,11 +173,8 @@ func (p *nistParameters) SharedKey(peerPublicKey > []byte) []byte { > + } > + > + xShared, _ := curve.ScalarMult(x, y, p.privateKey) > +- sharedKey := make([]byte, (curve.Params().BitSize+7)>>3) > +- xBytes := xShared.Bytes() > +- copy(sharedKey[len(sharedKey)-len(xBytes):], xBytes) > +- > +- return sharedKey > ++ sharedKey := make([]byte, (curve.Params().BitSize+7)/8) > ++ return xShared.FillBytes(sharedKey) > + } > + > + type x25519Parameters struct { > +diff --git a/src/crypto/x509/sec1.go b/src/crypto/x509/sec1.go > +index 0bfb90cd5464a..52c108ff1d624 100644 > +--- a/src/crypto/x509/sec1.go > ++++ b/src/crypto/x509/sec1.go > +@@ -52,13 +52,10 @@ func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, > error) { > + // marshalECPrivateKey marshals an EC private key into ASN.1, DER format and > + // sets the curve ID to the given OID, or omits it if OID is nil. > + func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid > asn1.ObjectIdentifier) ([]byte, error) { > +- privateKeyBytes := key.D.Bytes() > +- paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) > +- copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], > privateKeyBytes) > +- > ++ privateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) > + return asn1.Marshal(ecPrivateKey{ > + Version: 1, > +- PrivateKey: paddedPrivateKey, > ++ PrivateKey: key.D.FillBytes(privateKey), > + NamedCurveOID: oid, > + PublicKey: asn1.BitString{Bytes: > elliptic.Marshal(key.Curve, key.X, key.Y)}, > + }) > +diff --git a/src/math/big/int.go b/src/math/big/int.go > +index 8816cf5266cc4..65f32487b58c0 100644 > +--- a/src/math/big/int.go > ++++ b/src/math/big/int.go > +@@ -447,11 +447,26 @@ func (z *Int) SetBytes(buf []byte) *Int { > + } > + > + // Bytes returns the absolute value of x as a big-endian byte slice. > ++// > ++// To use a fixed length slice, or a preallocated one, use FillBytes. > + func (x *Int) Bytes() []byte { > + buf := make([]byte, len(x.abs)*_S) > + return buf[x.abs.bytes(buf):] > + } > + > ++// FillBytes sets buf to the absolute value of x, storing it as a > zero-extended > ++// big-endian byte slice, and returns buf. > ++// > ++// If the absolute value of x doesn't fit in buf, FillBytes will panic. > ++func (x *Int) FillBytes(buf []byte) []byte { > ++ // Clear whole buffer. (This gets optimized into a memclr.) > ++ for i := range buf { > ++ buf[i] = 0 > ++ } > ++ x.abs.bytes(buf) > ++ return buf > ++} > ++ > + // BitLen returns the length of the absolute value of x in bits. > + // The bit length of 0 is 0. > + func (x *Int) BitLen() int { > +diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go > +index e3a1587b3f0ad..3c8557323a032 100644 > +--- a/src/math/big/int_test.go > ++++ b/src/math/big/int_test.go > +@@ -1840,3 +1840,57 @@ func BenchmarkDiv(b *testing.B) { > + }) > + } > + } > ++ > ++func TestFillBytes(t *testing.T) { > ++ checkResult := func(t *testing.T, buf []byte, want *Int) { > ++ t.Helper() > ++ got := new(Int).SetBytes(buf) > ++ if got.CmpAbs(want) != 0 { > ++ t.Errorf("got 0x%x, want 0x%x: %x", got, want, buf) > ++ } > ++ } > ++ panics := func(f func()) (panic bool) { > ++ defer func() { panic = recover() != nil }() > ++ f() > ++ return > ++ } > ++ > ++ for _, n := range []string{ > ++ "0", > ++ "1000", > ++ "0xffffffff", > ++ "-0xffffffff", > ++ "0xffffffffffffffff", > ++ "0x10000000000000000", > ++ "0xabababababababababababababababababababababababababa", > ++ > "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", > ++ } { > ++ t.Run(n, func(t *testing.T) { > ++ t.Logf(n) > ++ x, ok := new(Int).SetString(n, 0) > ++ if !ok { > ++ panic("invalid test entry") > ++ } > ++ > ++ // Perfectly sized buffer. > ++ byteLen := (x.BitLen() + 7) / 8 > ++ buf := make([]byte, byteLen) > ++ checkResult(t, x.FillBytes(buf), x) > ++ > ++ // Way larger, checking all bytes get zeroed. > ++ buf = make([]byte, 100) > ++ for i := range buf { > ++ buf[i] = 0xff > ++ } > ++ checkResult(t, x.FillBytes(buf), x) > ++ > ++ // Too small. > ++ if byteLen > 0 { > ++ buf = make([]byte, byteLen-1) > ++ if !panics(func() { x.FillBytes(buf) }) { > ++ t.Errorf("expected panic for small > buffer and value %x", x) > ++ } > ++ } > ++ }) > ++ } > ++} > +diff --git a/src/math/big/nat.go b/src/math/big/nat.go > +index c31ec5156b81d..6a3989bf9d82b 100644 > +--- a/src/math/big/nat.go > ++++ b/src/math/big/nat.go > +@@ -1476,19 +1476,26 @@ func (z nat) expNNMontgomery(x, y, m nat) nat { > + } > + > + // bytes writes the value of z into buf using big-endian encoding. > +-// len(buf) must be >= len(z)*_S. The value of z is encoded in the > +-// slice buf[i:]. The number i of unused bytes at the beginning of > +-// buf is returned as result. > ++// The value of z is encoded in the slice buf[i:]. If the value of z > ++// cannot be represented in buf, bytes panics. The number i of unused > ++// bytes at the beginning of buf is returned as result. > + func (z nat) bytes(buf []byte) (i int) { > + i = len(buf) > + for _, d := range z { > + for j := 0; j < _S; j++ { > + i-- > +- buf[i] = byte(d) > ++ if i >= 0 { > ++ buf[i] = byte(d) > ++ } else if byte(d) != 0 { > ++ panic("math/big: buffer too small to fit > value") > ++ } > + d >>= 8 > + } > + } > + > ++ if i < 0 { > ++ i = 0 > ++ } > + for i < len(buf) && buf[i] == 0 { > + i++ > + } > diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre3.patch > b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre3.patch > new file mode 100644 > index 0000000000..ae9fcc170c > --- /dev/null > +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287-pre3.patch > @@ -0,0 +1,86 @@ > +From 8f676144ad7b7c91adb0c6e1ec89aaa6283c6807 Mon Sep 17 00:00:00 2001 > +From: Himanshu Kishna Srivastava <28himan...@gmail.com> > +Date: Tue, 16 Mar 2021 22:37:46 +0530 > +Subject: [PATCH] crypto/rsa: fix salt length calculation with > + PSSSaltLengthAuto > + > +When PSSSaltLength is set, the maximum salt length must equal: > + > + (modulus_key_size - 1 + 7)/8 - hash_length - 2 > +and for example, with a 4096 bit modulus key, and a SHA-1 hash, > +it should be: > + > + (4096 -1 + 7)/8 - 20 - 2 = 490 > +Previously we'd encounter this error: > + > + crypto/rsa: key size too small for PSS signature > + > +Fixes #42741 > + > +Change-Id: I18bb82c41c511d564b3f4c443f4b3a38ab010ac5 > +Reviewed-on: https://go-review.googlesource.com/c/go/+/302230 > +Reviewed-by: Emmanuel Odeke <emman...@orijtech.com> > +Reviewed-by: Filippo Valsorda <fili...@golang.org> > +Trust: Emmanuel Odeke <emman...@orijtech.com> > +Run-TryBot: Emmanuel Odeke <emman...@orijtech.com> > +TryBot-Result: Go Bot <go...@golang.org> > + > +Upstream-Status: Backport > [https://github.com/golang/go/commit/8f676144ad7b7c91adb0c6e1ec89aaa6283c6807] > +CVE: CVE-2023-45287 #Dependency Patch3 > +Signed-off-by: Vijay Anusuri <vanus...@mvista.com> > +--- > + src/crypto/rsa/pss.go | 2 +- > + src/crypto/rsa/pss_test.go | 20 +++++++++++++++++++- > + 2 files changed, 20 insertions(+), 2 deletions(-) > + > +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go > +index b2adbedb28fa8..814522de8181f 100644 > +--- a/src/crypto/rsa/pss.go > ++++ b/src/crypto/rsa/pss.go > +@@ -269,7 +269,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash > crypto.Hash, digest []byte, > + saltLength := opts.saltLength() > + switch saltLength { > + case PSSSaltLengthAuto: > +- saltLength = priv.Size() - 2 - hash.Size() > ++ saltLength = (priv.N.BitLen()-1+7)/8 - 2 - hash.Size() > + case PSSSaltLengthEqualsHash: > + saltLength = hash.Size() > + } > +diff --git a/src/crypto/rsa/pss_test.go b/src/crypto/rsa/pss_test.go > +index dfa8d8bb5ad02..c3a6d468497cd 100644 > +--- a/src/crypto/rsa/pss_test.go > ++++ b/src/crypto/rsa/pss_test.go > +@@ -12,7 +12,7 @@ import ( > + _ "crypto/md5" > + "crypto/rand" > + "crypto/sha1" > +- _ "crypto/sha256" > ++ "crypto/sha256" > + "encoding/hex" > + "math/big" > + "os" > +@@ -233,6 +233,24 @@ func TestPSSSigning(t *testing.T) { > + } > + } > + > ++func TestSignWithPSSSaltLengthAuto(t *testing.T) { > ++ key, err := GenerateKey(rand.Reader, 513) > ++ if err != nil { > ++ t.Fatal(err) > ++ } > ++ digest := sha256.Sum256([]byte("message")) > ++ signature, err := key.Sign(rand.Reader, digest[:], &PSSOptions{ > ++ SaltLength: PSSSaltLengthAuto, > ++ Hash: crypto.SHA256, > ++ }) > ++ if err != nil { > ++ t.Fatal(err) > ++ } > ++ if len(signature) == 0 { > ++ t.Fatal("empty signature returned") > ++ } > ++} > ++ > + func bigFromHex(hex string) *big.Int { > + n, ok := new(big.Int).SetString(hex, 16) > + if !ok { > diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-45287.patch > b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287.patch > new file mode 100644 > index 0000000000..a62c1258f8 > --- /dev/null > +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-45287.patch > @@ -0,0 +1,1697 @@ > +From 8a81fdf165facdcefa06531de5af98a4db343035 Mon Sep 17 00:00:00 2001 > +From: =?UTF-8?q?L=C3=BAc=C3=A1s=20Meier?= <cronoki...@gmail.com> > +Date: Tue, 8 Jun 2021 21:36:06 +0200 > +Subject: [PATCH] crypto/rsa: replace big.Int for encryption and decryption > + > +Infamously, big.Int does not provide constant-time arithmetic, making > +its use in cryptographic code quite tricky. RSA uses big.Int > +pervasively, in its public API, for key generation, precomputation, and > +for encryption and decryption. This is a known problem. One mitigation, > +blinding, is already in place during decryption. This helps mitigate the > +very leaky exponentiation operation. Because big.Int is fundamentally > +not constant-time, it's unfortunately difficult to guarantee that > +mitigations like these are completely effective. > + > +This patch removes the use of big.Int for encryption and decryption, > +replacing it with an internal nat type instead. Signing and verification > +are also affected, because they depend on encryption and decryption. > + > +Overall, this patch degrades performance by 55% for private key > +operations, and 4-5x for (much faster) public key operations. > +(Signatures do both, so the slowdown is worse than decryption.) > + > +name old time/op new time/op delta > +DecryptPKCS1v15/2048-8 1.50ms ± 0% 2.34ms ± 0% +56.44% (p=0.000 > n=8+10) > +DecryptPKCS1v15/3072-8 4.40ms ± 0% 6.79ms ± 0% +54.33% (p=0.000 > n=10+9) > +DecryptPKCS1v15/4096-8 9.31ms ± 0% 15.14ms ± 0% +62.60% (p=0.000 > n=10+10) > +EncryptPKCS1v15/2048-8 8.16µs ± 0% 355.58µs ± 0% +4258.90% (p=0.000 > n=10+9) > +DecryptOAEP/2048-8 1.50ms ± 0% 2.34ms ± 0% +55.68% (p=0.000 > n=10+9) > +EncryptOAEP/2048-8 8.51µs ± 0% 355.95µs ± 0% +4082.75% (p=0.000 > n=10+9) > +SignPKCS1v15/2048-8 1.51ms ± 0% 2.69ms ± 0% +77.94% (p=0.000 > n=10+10) > +VerifyPKCS1v15/2048-8 7.25µs ± 0% 354.34µs ± 0% +4789.52% (p=0.000 > n=9+9) > +SignPSS/2048-8 1.51ms ± 0% 2.70ms ± 0% +78.80% (p=0.000 > n=9+10) > +VerifyPSS/2048-8 8.27µs ± 1% 355.65µs ± 0% +4199.39% (p=0.000 > n=10+10) > + > +Keep in mind that this is without any assembly at all, and that further > +improvements are likely possible. I think having a review of the logic > +and the cryptography would be a good idea at this stage, before we > +complicate the code too much through optimization. > + > +The bulk of the work is in nat.go. This introduces two new types: nat, > +representing natural numbers, and modulus, representing moduli used in > +modular arithmetic. > + > +A nat has an "announced size", which may be larger than its "true size", > +the number of bits needed to represent this number. Operations on a nat > +will only ever leak its announced size, never its true size, or other > +information about its value. The size of a nat is always clear based on > +how its value is set. For example, x.mod(y, m) will make the announced > +size of x match that of m, since x is reduced modulo m. > + > +Operations assume that the announced size of the operands match what's > +expected (with a few exceptions). For example, x.modAdd(y, m) assumes > +that x and y have the same announced size as m, and that they're reduced > +modulo m. > + > +Nats are represented over unsatured bits.UintSize - 1 bit limbs. This > +means that we can't reuse the assembly routines for big.Int, which use > +saturated bits.UintSize limbs. The advantage of unsaturated limbs is > +that it makes Montgomery multiplication faster, by needing fewer > +registers in a hot loop. This makes exponentiation faster, which > +consists of many Montgomery multiplications. > + > +Moduli use nat internally. Unlike nat, the true size of a modulus always > +matches its announced size. When creating a modulus, any zero padding is > +removed. Moduli will also precompute constants when created, which is > +another reason why having a separate type is desirable. > + > +Updates #20654 > + > +Co-authored-by: Filippo Valsorda <fili...@golang.org> > +Change-Id: I73b61f87d58ab912e80a9644e255d552cbadcced > +Reviewed-on: https://go-review.googlesource.com/c/go/+/326012 > +Run-TryBot: Filippo Valsorda <fili...@golang.org> > +TryBot-Result: Gopher Robot <go...@golang.org> > +Reviewed-by: Roland Shoemaker <rol...@golang.org> > +Reviewed-by: Joedian Reid <joed...@golang.org> > + > +Upstream-Status: Backport > [https://github.com/golang/go/commit/8a81fdf165facdcefa06531de5af98a4db343035] > +CVE: CVE-2023-45287 > +Signed-off-by: Vijay Anusuri <vanus...@mvista.com> > +--- > + src/crypto/rsa/example_test.go | 21 +- > + src/crypto/rsa/nat.go | 626 +++++++++++++++++++++++++++++++++ > + src/crypto/rsa/nat_test.go | 384 ++++++++++++++++++++ > + src/crypto/rsa/pkcs1v15.go | 47 +-- > + src/crypto/rsa/pss.go | 50 ++- > + src/crypto/rsa/pss_test.go | 10 +- > + src/crypto/rsa/rsa.go | 174 ++++----- > + 7 files changed, 1143 insertions(+), 169 deletions(-) > + create mode 100644 src/crypto/rsa/nat.go > + create mode 100644 src/crypto/rsa/nat_test.go > + > +diff --git a/src/crypto/rsa/example_test.go b/src/crypto/rsa/example_test.go > +index 1435b70..1963609 100644 > +--- a/src/crypto/rsa/example_test.go > ++++ b/src/crypto/rsa/example_test.go > +@@ -12,7 +12,6 @@ import ( > + "crypto/sha256" > + "encoding/hex" > + "fmt" > +- "io" > + "os" > + ) > + > +@@ -36,21 +35,17 @@ import ( > + // a buffer that contains a random key. Thus, if the RSA result isn't > + // well-formed, the implementation uses a random key in constant time. > + func ExampleDecryptPKCS1v15SessionKey() { > +- // crypto/rand.Reader is a good source of entropy for blinding the RSA > +- // operation. > +- rng := rand.Reader > +- > + // The hybrid scheme should use at least a 16-byte symmetric key. Here > + // we read the random key that will be used if the RSA decryption > isn't > + // well-formed. > + key := make([]byte, 32) > +- if _, err := io.ReadFull(rng, key); err != nil { > ++ if _, err := rand.Read(key); err != nil { > + panic("RNG failure") > + } > + > + rsaCiphertext, _ := hex.DecodeString("aabbccddeeff") > + > +- if err := DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, > rsaCiphertext, key); err != nil { > ++ if err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, > rsaCiphertext, key); err != nil { > + // Any errors that result will be “public” – meaning that they > + // can be determined without any secret information. (For > + // instance, if the length of key is impossible given the RSA > +@@ -86,10 +81,6 @@ func ExampleDecryptPKCS1v15SessionKey() { > + } > + > + func ExampleSignPKCS1v15() { > +- // crypto/rand.Reader is a good source of entropy for blinding the RSA > +- // operation. > +- rng := rand.Reader > +- > + message := []byte("message to be signed") > + > + // Only small messages can be signed directly; thus the hash of a > +@@ -99,7 +90,7 @@ func ExampleSignPKCS1v15() { > + // of writing (2016). > + hashed := sha256.Sum256(message) > + > +- signature, err := SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, > hashed[:]) > ++ signature, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA256, > hashed[:]) > + if err != nil { > + fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err) > + return > +@@ -151,11 +142,7 @@ func ExampleDecryptOAEP() { > + ciphertext, _ := > hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460") > + label := []byte("orders") > + > +- // crypto/rand.Reader is a good source of entropy for blinding the RSA > +- // operation. > +- rng := rand.Reader > +- > +- plaintext, err := DecryptOAEP(sha256.New(), rng, test2048Key, > ciphertext, label) > ++ plaintext, err := DecryptOAEP(sha256.New(), nil, test2048Key, > ciphertext, label) > + if err != nil { > + fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err) > + return > +diff --git a/src/crypto/rsa/nat.go b/src/crypto/rsa/nat.go > +new file mode 100644 > +index 0000000..da521c2 > +--- /dev/null > ++++ b/src/crypto/rsa/nat.go > +@@ -0,0 +1,626 @@ > ++// Copyright 2021 The Go Authors. All rights reserved. > ++// Use of this source code is governed by a BSD-style > ++// license that can be found in the LICENSE file. > ++ > ++package rsa > ++ > ++import ( > ++ "math/big" > ++ "math/bits" > ++) > ++ > ++const ( > ++ // _W is the number of bits we use for our limbs. > ++ _W = bits.UintSize - 1 > ++ // _MASK selects _W bits from a full machine word. > ++ _MASK = (1 << _W) - 1 > ++) > ++ > ++// choice represents a constant-time boolean. The value of choice is always > ++// either 1 or 0. We use an int instead of bool in order to make decisions > in > ++// constant time by turning it into a mask. > ++type choice uint > ++ > ++func not(c choice) choice { return 1 ^ c } > ++ > ++const yes = choice(1) > ++const no = choice(0) > ++ > ++// ctSelect returns x if on == 1, and y if on == 0. The execution time of > this > ++// function does not depend on its inputs. If on is any value besides 1 or > 0, > ++// the result is undefined. > ++func ctSelect(on choice, x, y uint) uint { > ++ // When on == 1, mask is 0b111..., otherwise mask is 0b000... > ++ mask := -uint(on) > ++ // When mask is all zeros, we just have y, otherwise, y cancels with > itself. > ++ return y ^ (mask & (y ^ x)) > ++} > ++ > ++// ctEq returns 1 if x == y, and 0 otherwise. The execution time of this > ++// function does not depend on its inputs. > ++func ctEq(x, y uint) choice { > ++ // If x != y, then either x - y or y - x will generate a carry. > ++ _, c1 := bits.Sub(x, y, 0) > ++ _, c2 := bits.Sub(y, x, 0) > ++ return not(choice(c1 | c2)) > ++} > ++ > ++// ctGeq returns 1 if x >= y, and 0 otherwise. The execution time of this > ++// function does not depend on its inputs. > ++func ctGeq(x, y uint) choice { > ++ // If x < y, then x - y generates a carry. > ++ _, carry := bits.Sub(x, y, 0) > ++ return not(choice(carry)) > ++} > ++ > ++// nat represents an arbitrary natural number > ++// > ++// Each nat has an announced length, which is the number of limbs it has > stored. > ++// Operations on this number are allowed to leak this length, but will not > leak > ++// any information about the values contained in those limbs. > ++type nat struct { > ++ // limbs is a little-endian representation in base 2^W with > ++ // W = bits.UintSize - 1. The top bit is always unset between > operations. > ++ // > ++ // The top bit is left unset to optimize Montgomery multiplication, > in the > ++ // inner loop of exponentiation. Using fully saturated limbs would > leave us > ++ // working with 129-bit numbers on 64-bit platforms, wasting a lot of > space, > ++ // and thus time. > ++ limbs []uint > ++} > ++ > ++// expand expands x to n limbs, leaving its value unchanged. > ++func (x *nat) expand(n int) *nat { > ++ for len(x.limbs) > n { > ++ if x.limbs[len(x.limbs)-1] != 0 { > ++ panic("rsa: internal error: shrinking nat") > ++ } > ++ x.limbs = x.limbs[:len(x.limbs)-1] > ++ } > ++ if cap(x.limbs) < n { > ++ newLimbs := make([]uint, n) > ++ copy(newLimbs, x.limbs) > ++ x.limbs = newLimbs > ++ return x > ++ } > ++ extraLimbs := x.limbs[len(x.limbs):n] > ++ for i := range extraLimbs { > ++ extraLimbs[i] = 0 > ++ } > ++ x.limbs = x.limbs[:n] > ++ return x > ++} > ++ > ++// reset returns a zero nat of n limbs, reusing x's storage if n <= > cap(x.limbs). > ++func (x *nat) reset(n int) *nat { > ++ if cap(x.limbs) < n { > ++ x.limbs = make([]uint, n) > ++ return x > ++ } > ++ for i := range x.limbs { > ++ x.limbs[i] = 0 > ++ } > ++ x.limbs = x.limbs[:n] > ++ return x > ++} > ++ > ++// clone returns a new nat, with the same value and announced length as x. > ++func (x *nat) clone() *nat { > ++ out := &nat{make([]uint, len(x.limbs))} > ++ copy(out.limbs, x.limbs) > ++ return out > ++} > ++ > ++// natFromBig creates a new natural number from a big.Int. > ++// > ++// The announced length of the resulting nat is based on the actual bit > size of > ++// the input, ignoring leading zeroes. > ++func natFromBig(x *big.Int) *nat { > ++ xLimbs := x.Bits() > ++ bitSize := bigBitLen(x) > ++ requiredLimbs := (bitSize + _W - 1) / _W > ++ > ++ out := &nat{make([]uint, requiredLimbs)} > ++ outI := 0 > ++ shift := 0 > ++ for i := range xLimbs { > ++ xi := uint(xLimbs[i]) > ++ out.limbs[outI] |= (xi << shift) & _MASK > ++ outI++ > ++ if outI == requiredLimbs { > ++ return out > ++ } > ++ out.limbs[outI] = xi >> (_W - shift) > ++ shift++ // this assumes bits.UintSize - _W = 1 > ++ if shift == _W { > ++ shift = 0 > ++ outI++ > ++ } > ++ } > ++ return out > ++} > ++ > ++// fillBytes sets bytes to x as a zero-extended big-endian byte slice. > ++// > ++// If bytes is not long enough to contain the number or at least > len(x.limbs)-1 > ++// limbs, or has zero length, fillBytes will panic. > ++func (x *nat) fillBytes(bytes []byte) []byte { > ++ if len(bytes) == 0 { > ++ panic("nat: fillBytes invoked with too small buffer") > ++ } > ++ for i := range bytes { > ++ bytes[i] = 0 > ++ } > ++ shift := 0 > ++ outI := len(bytes) - 1 > ++ for i, limb := range x.limbs { > ++ remainingBits := _W > ++ for remainingBits >= 8 { > ++ bytes[outI] |= byte(limb) << shift > ++ consumed := 8 - shift > ++ limb >>= consumed > ++ remainingBits -= consumed > ++ shift = 0 > ++ outI-- > ++ if outI < 0 { > ++ if limb != 0 || i < len(x.limbs)-1 { > ++ panic("nat: fillBytes invoked with > too small buffer") > ++ } > ++ return bytes > ++ } > ++ } > ++ bytes[outI] = byte(limb) > ++ shift = remainingBits > ++ } > ++ return bytes > ++} > ++ > ++// natFromBytes converts a slice of big-endian bytes into a nat. > ++// > ++// The announced length of the output depends on the length of bytes. Unlike > ++// big.Int, creating a nat will not remove leading zeros. > ++func natFromBytes(bytes []byte) *nat { > ++ bitSize := len(bytes) * 8 > ++ requiredLimbs := (bitSize + _W - 1) / _W > ++ > ++ out := &nat{make([]uint, requiredLimbs)} > ++ outI := 0 > ++ shift := 0 > ++ for i := len(bytes) - 1; i >= 0; i-- { > ++ bi := bytes[i] > ++ out.limbs[outI] |= uint(bi) << shift > ++ shift += 8 > ++ if shift >= _W { > ++ shift -= _W > ++ out.limbs[outI] &= _MASK > ++ outI++ > ++ if shift > 0 { > ++ out.limbs[outI] = uint(bi) >> (8 - shift) > ++ } > ++ } > ++ } > ++ return out > ++} > ++ > ++// cmpEq returns 1 if x == y, and 0 otherwise. > ++// > ++// Both operands must have the same announced length. > ++func (x *nat) cmpEq(y *nat) choice { > ++ // Eliminate bounds checks in the loop. > ++ size := len(x.limbs) > ++ xLimbs := x.limbs[:size] > ++ yLimbs := y.limbs[:size] > ++ > ++ equal := yes > ++ for i := 0; i < size; i++ { > ++ equal &= ctEq(xLimbs[i], yLimbs[i]) > ++ } > ++ return equal > ++} > ++ > ++// cmpGeq returns 1 if x >= y, and 0 otherwise. > ++// > ++// Both operands must have the same announced length. > ++func (x *nat) cmpGeq(y *nat) choice { > ++ // Eliminate bounds checks in the loop. > ++ size := len(x.limbs) > ++ xLimbs := x.limbs[:size] > ++ yLimbs := y.limbs[:size] > ++ > ++ var c uint > ++ for i := 0; i < size; i++ { > ++ c = (xLimbs[i] - yLimbs[i] - c) >> _W > ++ } > ++ // If there was a carry, then subtracting y underflowed, so > ++ // x is not greater than or equal to y. > ++ return not(choice(c)) > ++} > ++ > ++// assign sets x <- y if on == 1, and does nothing otherwise. > ++// > ++// Both operands must have the same announced length. > ++func (x *nat) assign(on choice, y *nat) *nat { > ++ // Eliminate bounds checks in the loop. > ++ size := len(x.limbs) > ++ xLimbs := x.limbs[:size] > ++ yLimbs := y.limbs[:size] > ++ > ++ for i := 0; i < size; i++ { > ++ xLimbs[i] = ctSelect(on, yLimbs[i], xLimbs[i]) > ++ } > ++ return x > ++} > ++ > ++// add computes x += y if on == 1, and does nothing otherwise. It returns > the > ++// carry of the addition regardless of on. > ++// > ++// Both operands must have the same announced length. > ++func (x *nat) add(on choice, y *nat) (c uint) { > ++ // Eliminate bounds checks in the loop. > ++ size := len(x.limbs) > ++ xLimbs := x.limbs[:size] > ++ yLimbs := y.limbs[:size] > ++ > ++ for i := 0; i < size; i++ { > ++ res := xLimbs[i] + yLimbs[i] + c > ++ xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i]) > ++ c = res >> _W > ++ } > ++ return > ++} > ++ > ++// sub computes x -= y if on == 1, and does nothing otherwise. It returns > the > ++// borrow of the subtraction regardless of on. > ++// > ++// Both operands must have the same announced length. > ++func (x *nat) sub(on choice, y *nat) (c uint) { > ++ // Eliminate bounds checks in the loop. > ++ size := len(x.limbs) > ++ xLimbs := x.limbs[:size] > ++ yLimbs := y.limbs[:size] > ++ > ++ for i := 0; i < size; i++ { > ++ res := xLimbs[i] - yLimbs[i] - c > ++ xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i]) > ++ c = res >> _W > ++ } > ++ return > ++} > ++ > ++// modulus is used for modular arithmetic, precomputing relevant constants. > ++// > ++// Moduli are assumed to be odd numbers. Moduli can also leak the exact > ++// number of bits needed to store their value, and are stored without > padding. > ++// > ++// Their actual value is still kept secret. > ++type modulus struct { > ++ // The underlying natural number for this modulus. > ++ // > ++ // This will be stored without any padding, and shouldn't alias with > any > ++ // other natural number being used. > ++ nat *nat > ++ leading int // number of leading zeros in the modulus > ++ m0inv uint // -nat.limbs[0]⁻¹ mod _W > ++} > ++ > ++// minusInverseModW computes -x⁻¹ mod _W with x odd. > ++// > ++// This operation is used to precompute a constant involved in Montgomery > ++// multiplication. > ++func minusInverseModW(x uint) uint { > ++ // Every iteration of this loop doubles the least-significant bits of > ++ // correct inverse in y. The first three bits are already correct > (1⁻¹ = 1, > ++ // 3⁻¹ = 3, 5⁻¹ = 5, and 7⁻¹ = 7 mod 8), so doubling five times is > enough > ++ // for 61 bits (and wastes only one iteration for 31 bits). > ++ // > ++ // See https://crypto.stackexchange.com/a/47496. > ++ y := x > ++ for i := 0; i < 5; i++ { > ++ y = y * (2 - x*y) > ++ } > ++ return (1 << _W) - (y & _MASK) > ++} > ++ > ++// modulusFromNat creates a new modulus from a nat. > ++// > ++// The nat should be odd, nonzero, and the number of significant bits in the > ++// number should be leakable. The nat shouldn't be reused. > ++func modulusFromNat(nat *nat) *modulus { > ++ m := &modulus{} > ++ m.nat = nat > ++ size := len(m.nat.limbs) > ++ for m.nat.limbs[size-1] == 0 { > ++ size-- > ++ } > ++ m.nat.limbs = m.nat.limbs[:size] > ++ m.leading = _W - bitLen(m.nat.limbs[size-1]) > ++ m.m0inv = minusInverseModW(m.nat.limbs[0]) > ++ return m > ++} > ++ > ++// bitLen is a version of bits.Len that only leaks the bit length of n, but > not > ++// its value. bits.Len and bits.LeadingZeros use a lookup table for the > ++// low-order bits on some architectures. > ++func bitLen(n uint) int { > ++ var len int > ++ // We assume, here and elsewhere, that comparison to zero is constant > time > ++ // with respect to different non-zero values. > ++ for n != 0 { > ++ len++ > ++ n >>= 1 > ++ } > ++ return len > ++} > ++ > ++// bigBitLen is a version of big.Int.BitLen that only leaks the bit length > of x, > ++// but not its value. big.Int.BitLen uses bits.Len. > ++func bigBitLen(x *big.Int) int { > ++ xLimbs := x.Bits() > ++ fullLimbs := len(xLimbs) - 1 > ++ topLimb := uint(xLimbs[len(xLimbs)-1]) > ++ return fullLimbs*bits.UintSize + bitLen(topLimb) > ++} > ++ > ++// modulusSize returns the size of m in bytes. > ++func modulusSize(m *modulus) int { > ++ bits := len(m.nat.limbs)*_W - int(m.leading) > ++ return (bits + 7) / 8 > ++} > ++ > ++// shiftIn calculates x = x << _W + y mod m. > ++// > ++// This assumes that x is already reduced mod m, and that y < 2^_W. > ++func (x *nat) shiftIn(y uint, m *modulus) *nat { > ++ d := new(nat).resetFor(m) > ++ > ++ // Eliminate bounds checks in the loop. > ++ size := len(m.nat.limbs) > ++ xLimbs := x.limbs[:size] > ++ dLimbs := d.limbs[:size] > ++ mLimbs := m.nat.limbs[:size] > ++ > ++ // Each iteration of this loop computes x = 2x + b mod m, where b is > a bit > ++ // from y. Effectively, it left-shifts x and adds y one bit at a time, > ++ // reducing it every time. > ++ // > ++ // To do the reduction, each iteration computes both 2x + b and 2x + > b - m. > ++ // The next iteration (and finally the return line) will use either > result > ++ // based on whether the subtraction underflowed. > ++ needSubtraction := no > ++ for i := _W - 1; i >= 0; i-- { > ++ carry := (y >> i) & 1 > ++ var borrow uint > ++ for i := 0; i < size; i++ { > ++ l := ctSelect(needSubtraction, dLimbs[i], xLimbs[i]) > ++ > ++ res := l<<1 + carry > ++ xLimbs[i] = res & _MASK > ++ carry = res >> _W > ++ > ++ res = xLimbs[i] - mLimbs[i] - borrow > ++ dLimbs[i] = res & _MASK > ++ borrow = res >> _W > ++ } > ++ // See modAdd for how carry (aka overflow), borrow (aka > underflow), and > ++ // needSubtraction relate. > ++ needSubtraction = ctEq(carry, borrow) > ++ } > ++ return x.assign(needSubtraction, d) > ++} > ++ > ++// mod calculates out = x mod m. > ++// > ++// This works regardless how large the value of x is. > ++// > ++// The output will be resized to the size of m and overwritten. > ++func (out *nat) mod(x *nat, m *modulus) *nat { > ++ out.resetFor(m) > ++ // Working our way from the most significant to the least significant > limb, > ++ // we can insert each limb at the least significant position, > shifting all > ++ // previous limbs left by _W. This way each limb will get shifted by > the > ++ // correct number of bits. We can insert at least N - 1 limbs without > ++ // overflowing m. After that, we need to reduce every time we shift. > ++ i := len(x.limbs) - 1 > ++ // For the first N - 1 limbs we can skip the actual shifting and > position > ++ // them at the shifted position, which starts at min(N - 2, i). > ++ start := len(m.nat.limbs) - 2 > ++ if i < start { > ++ start = i > ++ } > ++ for j := start; j >= 0; j-- { > ++ out.limbs[j] = x.limbs[i] > ++ i-- > ++ } > ++ // We shift in the remaining limbs, reducing modulo m each time. > ++ for i >= 0 { > ++ out.shiftIn(x.limbs[i], m) > ++ i-- > ++ } > ++ return out > ++} > ++ > ++// expandFor ensures out has the right size to work with operations modulo > m. > ++// > ++// This assumes that out has as many or fewer limbs than m, or that the > extra > ++// limbs are all zero (which may happen when decoding a value that has > leading > ++// zeroes in its bytes representation that spill over the limb threshold). > ++func (out *nat) expandFor(m *modulus) *nat { > ++ return out.expand(len(m.nat.limbs)) > ++} > ++ > ++// resetFor ensures out has the right size to work with operations modulo m. > ++// > ++// out is zeroed and may start at any size. > ++func (out *nat) resetFor(m *modulus) *nat { > ++ return out.reset(len(m.nat.limbs)) > ++} > ++ > ++// modSub computes x = x - y mod m. > ++// > ++// The length of both operands must be the same as the modulus. Both > operands > ++// must already be reduced modulo m. > ++func (x *nat) modSub(y *nat, m *modulus) *nat { > ++ underflow := x.sub(yes, y) > ++ // If the subtraction underflowed, add m. > ++ x.add(choice(underflow), m.nat) > ++ return x > ++} > ++ > ++// modAdd computes x = x + y mod m. > ++// > ++// The length of both operands must be the same as the modulus. Both > operands > ++// must already be reduced modulo m. > ++func (x *nat) modAdd(y *nat, m *modulus) *nat { > ++ overflow := x.add(yes, y) > ++ underflow := not(x.cmpGeq(m.nat)) // x < m > ++ > ++ // Three cases are possible: > ++ // > ++ // - overflow = 0, underflow = 0 > ++ // > ++ // In this case, addition fits in our limbs, but we can still > subtract away > ++ // m without an underflow, so we need to perform the subtraction to > reduce > ++ // our result. > ++ // > ++ // - overflow = 0, underflow = 1 > ++ // > ++ // The addition fits in our limbs, but we can't subtract m without > ++ // underflowing. The result is already reduced. > ++ // > ++ // - overflow = 1, underflow = 1 > ++ // > ++ // The addition does not fit in our limbs, and the subtraction's > borrow > ++ // would cancel out with the addition's carry. We need to subtract m > to > ++ // reduce our result. > ++ // > ++ // The overflow = 1, underflow = 0 case is not possible, because y is > at > ++ // most m - 1, and if adding m - 1 overflows, then subtracting m must > ++ // necessarily underflow. > ++ needSubtraction := ctEq(overflow, uint(underflow)) > ++ > ++ x.sub(needSubtraction, m.nat) > ++ return x > ++} > ++ > ++// montgomeryRepresentation calculates x = x * R mod m, with R = 2^(_W * n) > and > ++// n = len(m.nat.limbs). > ++// > ++// Faster Montgomery multiplication replaces standard modular > multiplication for > ++// numbers in this representation. > ++// > ++// This assumes that x is already reduced mod m. > ++func (x *nat) montgomeryRepresentation(m *modulus) *nat { > ++ for i := 0; i < len(m.nat.limbs); i++ { > ++ x.shiftIn(0, m) // x = x * 2^_W mod m > ++ } > ++ return x > ++} > ++ > ++// montgomeryMul calculates d = a * b / R mod m, with R = 2^(_W * n) and > ++// n = len(m.nat.limbs), using the Montgomery Multiplication technique. > ++// > ++// All inputs should be the same length, not aliasing d, and already > ++// reduced modulo m. d will be resized to the size of m and overwritten. > ++func (d *nat) montgomeryMul(a *nat, b *nat, m *modulus) *nat { > ++ // See > https://bearssl.org/bigint.html#montgomery-reduction-and-multiplication > ++ // for a description of the algorithm. > ++ > ++ // Eliminate bounds checks in the loop. > ++ size := len(m.nat.limbs) > ++ aLimbs := a.limbs[:size] > ++ bLimbs := b.limbs[:size] > ++ dLimbs := d.resetFor(m).limbs[:size] > ++ mLimbs := m.nat.limbs[:size] > ++ > ++ var overflow uint > ++ for i := 0; i < size; i++ { > ++ f := ((dLimbs[0] + aLimbs[i]*bLimbs[0]) * m.m0inv) & _MASK > ++ carry := uint(0) > ++ for j := 0; j < size; j++ { > ++ // z = d[j] + a[i] * b[j] + f * m[j] + carry <= > 2^(2W+1) - 2^(W+1) + 2^W > ++ hi, lo := bits.Mul(aLimbs[i], bLimbs[j]) > ++ z_lo, c := bits.Add(dLimbs[j], lo, 0) > ++ z_hi, _ := bits.Add(0, hi, c) > ++ hi, lo = bits.Mul(f, mLimbs[j]) > ++ z_lo, c = bits.Add(z_lo, lo, 0) > ++ z_hi, _ = bits.Add(z_hi, hi, c) > ++ z_lo, c = bits.Add(z_lo, carry, 0) > ++ z_hi, _ = bits.Add(z_hi, 0, c) > ++ if j > 0 { > ++ dLimbs[j-1] = z_lo & _MASK > ++ } > ++ carry = z_hi<<1 | z_lo>>_W // carry <= 2^(W+1) - 2 > ++ } > ++ z := overflow + carry // z <= 2^(W+1) - 1 > ++ dLimbs[size-1] = z & _MASK > ++ overflow = z >> _W // overflow <= 1 > ++ } > ++ // See modAdd for how overflow, underflow, and needSubtraction relate. > ++ underflow := not(d.cmpGeq(m.nat)) // d < m > ++ needSubtraction := ctEq(overflow, uint(underflow)) > ++ d.sub(needSubtraction, m.nat) > ++ > ++ return d > ++} > ++ > ++// modMul calculates x *= y mod m. > ++// > ++// x and y must already be reduced modulo m, they must share its announced > ++// length, and they may not alias. > ++func (x *nat) modMul(y *nat, m *modulus) *nat { > ++ // A Montgomery multiplication by a value out of the Montgomery domain > ++ // takes the result out of Montgomery representation. > ++ xR := x.clone().montgomeryRepresentation(m) // xR = x * R mod m > ++ return x.montgomeryMul(xR, y, m) // x = xR * y / R mod m > ++} > ++ > ++// exp calculates out = x^e mod m. > ++// > ++// The exponent e is represented in big-endian order. The output will be > resized > ++// to the size of m and overwritten. x must already be reduced modulo m. > ++func (out *nat) exp(x *nat, e []byte, m *modulus) *nat { > ++ // We use a 4 bit window. For our RSA workload, 4 bit windows are > faster > ++ // than 2 bit windows, but use an extra 12 nats worth of scratch > space. > ++ // Using bit sizes that don't divide 8 are more complex to implement. > ++ table := make([]*nat, (1<<4)-1) // table[i] = x ^ (i+1) > ++ table[0] = x.clone().montgomeryRepresentation(m) > ++ for i := 1; i < len(table); i++ { > ++ table[i] = new(nat).expandFor(m) > ++ table[i].montgomeryMul(table[i-1], table[0], m) > ++ } > ++ > ++ out.resetFor(m) > ++ out.limbs[0] = 1 > ++ out.montgomeryRepresentation(m) > ++ t0 := new(nat).expandFor(m) > ++ t1 := new(nat).expandFor(m) > ++ for _, b := range e { > ++ for _, j := range []int{4, 0} { > ++ // Square four times. > ++ t1.montgomeryMul(out, out, m) > ++ out.montgomeryMul(t1, t1, m) > ++ t1.montgomeryMul(out, out, m) > ++ out.montgomeryMul(t1, t1, m) > ++ > ++ // Select x^k in constant time from the table. > ++ k := uint((b >> j) & 0b1111) > ++ for i := range table { > ++ t0.assign(ctEq(k, uint(i+1)), table[i]) > ++ } > ++ > ++ // Multiply by x^k, discarding the result if k = 0. > ++ t1.montgomeryMul(out, t0, m) > ++ out.assign(not(ctEq(k, 0)), t1) > ++ } > ++ } > ++ > ++ // By Montgomery multiplying with 1 not in Montgomery representation, > we > ++ // convert out back from Montgomery representation, because it works > out to > ++ // dividing by R. > ++ t0.assign(yes, out) > ++ t1.resetFor(m) > ++ t1.limbs[0] = 1 > ++ out.montgomeryMul(t0, t1, m) > ++ > ++ return out > ++} > +diff --git a/src/crypto/rsa/nat_test.go b/src/crypto/rsa/nat_test.go > +new file mode 100644 > +index 0000000..3e6eb10 > +--- /dev/null > ++++ b/src/crypto/rsa/nat_test.go > +@@ -0,0 +1,384 @@ > ++// Copyright 2021 The Go Authors. All rights reserved. > ++// Use of this source code is governed by a BSD-style > ++// license that can be found in the LICENSE file. > ++ > ++package rsa > ++ > ++import ( > ++ "bytes" > ++ "math/big" > ++ "math/bits" > ++ "math/rand" > ++ "reflect" > ++ "testing" > ++ "testing/quick" > ++) > ++ > ++// Generate generates an even nat. It's used by testing/quick to produce > random > ++// *nat values for quick.Check invocations. > ++func (*nat) Generate(r *rand.Rand, size int) reflect.Value { > ++ limbs := make([]uint, size) > ++ for i := 0; i < size; i++ { > ++ limbs[i] = uint(r.Uint64()) & ((1 << _W) - 2) > ++ } > ++ return reflect.ValueOf(&nat{limbs}) > ++} > ++ > ++func testModAddCommutative(a *nat, b *nat) bool { > ++ mLimbs := make([]uint, len(a.limbs)) > ++ for i := 0; i < len(mLimbs); i++ { > ++ mLimbs[i] = _MASK > ++ } > ++ m := modulusFromNat(&nat{mLimbs}) > ++ aPlusB := a.clone() > ++ aPlusB.modAdd(b, m) > ++ bPlusA := b.clone() > ++ bPlusA.modAdd(a, m) > ++ return aPlusB.cmpEq(bPlusA) == 1 > ++} > ++ > ++func TestModAddCommutative(t *testing.T) { > ++ err := quick.Check(testModAddCommutative, &quick.Config{}) > ++ if err != nil { > ++ t.Error(err) > ++ } > ++} > ++ > ++func testModSubThenAddIdentity(a *nat, b *nat) bool { > ++ mLimbs := make([]uint, len(a.limbs)) > ++ for i := 0; i < len(mLimbs); i++ { > ++ mLimbs[i] = _MASK > ++ } > ++ m := modulusFromNat(&nat{mLimbs}) > ++ original := a.clone() > ++ a.modSub(b, m) > ++ a.modAdd(b, m) > ++ return a.cmpEq(original) == 1 > ++} > ++ > ++func TestModSubThenAddIdentity(t *testing.T) { > ++ err := quick.Check(testModSubThenAddIdentity, &quick.Config{}) > ++ if err != nil { > ++ t.Error(err) > ++ } > ++} > ++ > ++func testMontgomeryRoundtrip(a *nat) bool { > ++ one := &nat{make([]uint, len(a.limbs))} > ++ one.limbs[0] = 1 > ++ aPlusOne := a.clone() > ++ aPlusOne.add(1, one) > ++ m := modulusFromNat(aPlusOne) > ++ monty := a.clone() > ++ monty.montgomeryRepresentation(m) > ++ aAgain := monty.clone() > ++ aAgain.montgomeryMul(monty, one, m) > ++ return a.cmpEq(aAgain) == 1 > ++} > ++ > ++func TestMontgomeryRoundtrip(t *testing.T) { > ++ err := quick.Check(testMontgomeryRoundtrip, &quick.Config{}) > ++ if err != nil { > ++ t.Error(err) > ++ } > ++} > ++ > ++func TestFromBig(t *testing.T) { > ++ expected := []byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, > 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} > ++ theBig := new(big.Int).SetBytes(expected) > ++ actual := natFromBig(theBig).fillBytes(make([]byte, len(expected))) > ++ if !bytes.Equal(actual, expected) { > ++ t.Errorf("%+x != %+x", actual, expected) > ++ } > ++} > ++ > ++func TestFillBytes(t *testing.T) { > ++ xBytes := []byte{0xAA, 0xFF, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} > ++ x := natFromBytes(xBytes) > ++ for l := 20; l >= len(xBytes); l-- { > ++ buf := make([]byte, l) > ++ rand.Read(buf) > ++ actual := x.fillBytes(buf) > ++ expected := make([]byte, l) > ++ copy(expected[l-len(xBytes):], xBytes) > ++ if !bytes.Equal(actual, expected) { > ++ t.Errorf("%d: %+v != %+v", l, actual, expected) > ++ } > ++ } > ++ for l := len(xBytes) - 1; l >= 0; l-- { > ++ (func() { > ++ defer func() { > ++ if recover() == nil { > ++ t.Errorf("%d: expected panic", l) > ++ } > ++ }() > ++ x.fillBytes(make([]byte, l)) > ++ })() > ++ } > ++} > ++ > ++func TestFromBytes(t *testing.T) { > ++ f := func(xBytes []byte) bool { > ++ if len(xBytes) == 0 { > ++ return true > ++ } > ++ actual := natFromBytes(xBytes).fillBytes(make([]byte, > len(xBytes))) > ++ if !bytes.Equal(actual, xBytes) { > ++ t.Errorf("%+x != %+x", actual, xBytes) > ++ return false > ++ } > ++ return true > ++ } > ++ > ++ err := quick.Check(f, &quick.Config{}) > ++ if err != nil { > ++ t.Error(err) > ++ } > ++ > ++ f([]byte{0xFF, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}) > ++ f(bytes.Repeat([]byte{0xFF}, _W)) > ++} > ++ > ++func TestShiftIn(t *testing.T) { > ++ if bits.UintSize != 64 { > ++ t.Skip("examples are only valid in 64 bit") > ++ } > ++ examples := []struct { > ++ m, x, expected []byte > ++ y uint64 > ++ }{{ > ++ m: []byte{13}, > ++ x: []byte{0}, > ++ y: 0x7FFF_FFFF_FFFF_FFFF, > ++ expected: []byte{7}, > ++ }, { > ++ m: []byte{13}, > ++ x: []byte{7}, > ++ y: 0x7FFF_FFFF_FFFF_FFFF, > ++ expected: []byte{11}, > ++ }, { > ++ m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, > 0x00, 0x0d}, > ++ x: make([]byte, 9), > ++ y: 0x7FFF_FFFF_FFFF_FFFF, > ++ expected: []byte{0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, > 0xff, 0xff}, > ++ }, { > ++ m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, > 0x00, 0x0d}, > ++ x: []byte{0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, > 0xff, 0xff}, > ++ y: 0, > ++ expected: []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, > 0x00, 0x08}, > ++ }} > ++ > ++ for i, tt := range examples { > ++ m := modulusFromNat(natFromBytes(tt.m)) > ++ got := natFromBytes(tt.x).expandFor(m).shiftIn(uint(tt.y), m) > ++ if got.cmpEq(natFromBytes(tt.expected).expandFor(m)) != 1 { > ++ t.Errorf("%d: got %x, expected %x", i, got, > tt.expected) > ++ } > ++ } > ++} > ++ > ++func TestModulusAndNatSizes(t *testing.T) { > ++ // These are 126 bit (2 * _W on 64-bit architectures) values, > serialized as > ++ // 128 bits worth of bytes. If leading zeroes are stripped, they fit > in two > ++ // limbs, if they are not, they fit in three. This can be a problem > because > ++ // modulus strips leading zeroes and nat does not. > ++ m := modulusFromNat(natFromBytes([]byte{ > ++ 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, > ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})) > ++ x := natFromBytes([]byte{ > ++ 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, > ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}) > ++ x.expandFor(m) // must not panic for shrinking > ++} > ++ > ++func TestExpand(t *testing.T) { > ++ sliced := []uint{1, 2, 3, 4} > ++ examples := []struct { > ++ in []uint > ++ n int > ++ out []uint > ++ }{{ > ++ []uint{1, 2}, > ++ 4, > ++ []uint{1, 2, 0, 0}, > ++ }, { > ++ sliced[:2], > ++ 4, > ++ []uint{1, 2, 0, 0}, > ++ }, { > ++ []uint{1, 2}, > ++ 2, > ++ []uint{1, 2}, > ++ }, { > ++ []uint{1, 2, 0}, > ++ 2, > ++ []uint{1, 2}, > ++ }} > ++ > ++ for i, tt := range examples { > ++ got := (&nat{tt.in}).expand(tt.n) > ++ if len(got.limbs) != len(tt.out) || got.cmpEq(&nat{tt.out}) > != 1 { > ++ t.Errorf("%d: got %x, expected %x", i, got, tt.out) > ++ } > ++ } > ++} > ++ > ++func TestMod(t *testing.T) { > ++ m := modulusFromNat(natFromBytes([]byte{0x06, 0x80, 0x00, 0x00, 0x00, > 0x00, 0x00, 0x00, 0x0d})) > ++ x := natFromBytes([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, > 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}) > ++ out := new(nat) > ++ out.mod(x, m) > ++ expected := natFromBytes([]byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, > 0x00, 0x00, 0x09}) > ++ if out.cmpEq(expected) != 1 { > ++ t.Errorf("%+v != %+v", out, expected) > ++ } > ++} > ++ > ++func TestModSub(t *testing.T) { > ++ m := modulusFromNat(&nat{[]uint{13}}) > ++ x := &nat{[]uint{6}} > ++ y := &nat{[]uint{7}} > ++ x.modSub(y, m) > ++ expected := &nat{[]uint{12}} > ++ if x.cmpEq(expected) != 1 { > ++ t.Errorf("%+v != %+v", x, expected) > ++ } > ++ x.modSub(y, m) > ++ expected = &nat{[]uint{5}} > ++ if x.cmpEq(expected) != 1 { > ++ t.Errorf("%+v != %+v", x, expected) > ++ } > ++} > ++ > ++func TestModAdd(t *testing.T) { > ++ m := modulusFromNat(&nat{[]uint{13}}) > ++ x := &nat{[]uint{6}} > ++ y := &nat{[]uint{7}} > ++ x.modAdd(y, m) > ++ expected := &nat{[]uint{0}} > ++ if x.cmpEq(expected) != 1 { > ++ t.Errorf("%+v != %+v", x, expected) > ++ } > ++ x.modAdd(y, m) > ++ expected = &nat{[]uint{7}} > ++ if x.cmpEq(expected) != 1 { > ++ t.Errorf("%+v != %+v", x, expected) > ++ } > ++} > ++ > ++func TestExp(t *testing.T) { > ++ m := modulusFromNat(&nat{[]uint{13}}) > ++ x := &nat{[]uint{3}} > ++ out := &nat{[]uint{0}} > ++ out.exp(x, []byte{12}, m) > ++ expected := &nat{[]uint{1}} > ++ if out.cmpEq(expected) != 1 { > ++ t.Errorf("%+v != %+v", out, expected) > ++ } > ++} > ++ > ++func makeBenchmarkModulus() *modulus { > ++ m := make([]uint, 32) > ++ for i := 0; i < 32; i++ { > ++ m[i] = _MASK > ++ } > ++ return modulusFromNat(&nat{limbs: m}) > ++} > ++ > ++func makeBenchmarkValue() *nat { > ++ x := make([]uint, 32) > ++ for i := 0; i < 32; i++ { > ++ x[i] = _MASK - 1 > ++ } > ++ return &nat{limbs: x} > ++} > ++ > ++func makeBenchmarkExponent() []byte { > ++ e := make([]byte, 256) > ++ for i := 0; i < 32; i++ { > ++ e[i] = 0xFF > ++ } > ++ return e > ++} > ++ > ++func BenchmarkModAdd(b *testing.B) { > ++ x := makeBenchmarkValue() > ++ y := makeBenchmarkValue() > ++ m := makeBenchmarkModulus() > ++ > ++ b.ResetTimer() > ++ for i := 0; i < b.N; i++ { > ++ x.modAdd(y, m) > ++ } > ++} > ++ > ++func BenchmarkModSub(b *testing.B) { > ++ x := makeBenchmarkValue() > ++ y := makeBenchmarkValue() > ++ m := makeBenchmarkModulus() > ++ > ++ b.ResetTimer() > ++ for i := 0; i < b.N; i++ { > ++ x.modSub(y, m) > ++ } > ++} > ++ > ++func BenchmarkMontgomeryRepr(b *testing.B) { > ++ x := makeBenchmarkValue() > ++ m := makeBenchmarkModulus() > ++ > ++ b.ResetTimer() > ++ for i := 0; i < b.N; i++ { > ++ x.montgomeryRepresentation(m) > ++ } > ++} > ++ > ++func BenchmarkMontgomeryMul(b *testing.B) { > ++ x := makeBenchmarkValue() > ++ y := makeBenchmarkValue() > ++ out := makeBenchmarkValue() > ++ m := makeBenchmarkModulus() > ++ > ++ b.ResetTimer() > ++ for i := 0; i < b.N; i++ { > ++ out.montgomeryMul(x, y, m) > ++ } > ++} > ++ > ++func BenchmarkModMul(b *testing.B) { > ++ x := makeBenchmarkValue() > ++ y := makeBenchmarkValue() > ++ m := makeBenchmarkModulus() > ++ > ++ b.ResetTimer() > ++ for i := 0; i < b.N; i++ { > ++ x.modMul(y, m) > ++ } > ++} > ++ > ++func BenchmarkExpBig(b *testing.B) { > ++ out := new(big.Int) > ++ exponentBytes := makeBenchmarkExponent() > ++ x := new(big.Int).SetBytes(exponentBytes) > ++ e := new(big.Int).SetBytes(exponentBytes) > ++ n := new(big.Int).SetBytes(exponentBytes) > ++ one := new(big.Int).SetUint64(1) > ++ n.Add(n, one) > ++ > ++ b.ResetTimer() > ++ for i := 0; i < b.N; i++ { > ++ out.Exp(x, e, n) > ++ } > ++} > ++ > ++func BenchmarkExp(b *testing.B) { > ++ x := makeBenchmarkValue() > ++ e := makeBenchmarkExponent() > ++ out := makeBenchmarkValue() > ++ m := makeBenchmarkModulus() > ++ > ++ b.ResetTimer() > ++ for i := 0; i < b.N; i++ { > ++ out.exp(x, e, m) > ++ } > ++} > +diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go > +index a216be3..4312f34 100644 > +--- a/src/crypto/rsa/pkcs1v15.go > ++++ b/src/crypto/rsa/pkcs1v15.go > +@@ -9,7 +9,6 @@ import ( > + "crypto/subtle" > + "errors" > + "io" > +- "math/big" > + > + "crypto/internal/randutil" > + ) > +@@ -58,14 +57,11 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg > []byte) ([]byte, error) > + em[len(em)-len(msg)-1] = 0 > + copy(mm, msg) > + > +- m := new(big.Int).SetBytes(em) > +- c := encrypt(new(big.Int), pub, m) > +- > +- return c.FillBytes(em), nil > ++ return encrypt(pub, em), nil > + } > + > + // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme > from PKCS#1 v1.5. > +-// If rand != nil, it uses RSA blinding to avoid timing side-channel > attacks. > ++// The rand parameter is legacy and ignored, and it can be as nil. > + // > + // Note that whether this function returns an error or not discloses secret > + // information. If an attacker can cause this function to run repeatedly and > +@@ -76,7 +72,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, > ciphertext []byte) ([]byt > + if err := checkPub(&priv.PublicKey); err != nil { > + return nil, err > + } > +- valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext) > ++ valid, out, index, err := decryptPKCS1v15(priv, ciphertext) > + if err != nil { > + return nil, err > + } > +@@ -87,7 +83,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, > ciphertext []byte) ([]byt > + } > + > + // DecryptPKCS1v15SessionKey decrypts a session key using RSA and the > padding scheme from PKCS#1 v1.5. > +-// If rand != nil, it uses RSA blinding to avoid timing side-channel > attacks. > ++// The rand parameter is legacy and ignored, and it can be as nil. > + // It returns an error if the ciphertext is the wrong length or if the > + // ciphertext is greater than the public modulus. Otherwise, no error is > + // returned. If the padding is valid, the resulting plaintext message is > copied > +@@ -114,7 +110,7 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv > *PrivateKey, ciphertext []by > + return ErrDecryption > + } > + > +- valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext) > ++ valid, em, index, err := decryptPKCS1v15(priv, ciphertext) > + if err != nil { > + return err > + } > +@@ -130,26 +126,24 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv > *PrivateKey, ciphertext []by > + return nil > + } > + > +-// decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation > if > +-// rand is not nil. It returns one or zero in valid that indicates whether > the > +-// plaintext was correctly structured. In either case, the plaintext is > +-// returned in em so that it may be read independently of whether it was > valid > +-// in order to maintain constant memory access patterns. If the plaintext > was > +-// valid then index contains the index of the original message in em. > +-func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) > (valid int, em []byte, index int, err error) { > ++// decryptPKCS1v15 decrypts ciphertext using priv. It returns one or zero in > ++// valid that indicates whether the plaintext was correctly structured. > ++// In either case, the plaintext is returned in em so that it may be read > ++// independently of whether it was valid in order to maintain constant > memory > ++// access patterns. If the plaintext was valid then index contains the > index of > ++// the original message in em, to allow constant time padding removal. > ++func decryptPKCS1v15(priv *PrivateKey, ciphertext []byte) (valid int, em > []byte, index int, err error) { > + k := priv.Size() > + if k < 11 { > + err = ErrDecryption > + return > + } > + > +- c := new(big.Int).SetBytes(ciphertext) > +- m, err := decrypt(rand, priv, c) > ++ em, err = decrypt(priv, ciphertext) > + if err != nil { > + return > + } > + > +- em = m.FillBytes(make([]byte, k)) > + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) > + secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2) > + > +@@ -221,8 +215,7 @@ var hashPrefixes = map[crypto.Hash][]byte{ > + // function. If hash is zero, hashed is signed directly. This isn't > + // advisable except for interoperability. > + // > +-// If rand is not nil then RSA blinding will be used to avoid timing > +-// side-channel attacks. > ++// The rand parameter is legacy and ignored, and it can be as nil. > + // > + // This function is deterministic. Thus, if the set of possible > + // messages is small, an attacker may be able to build a map from > +@@ -249,13 +242,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, > hash crypto.Hash, hashed []b > + copy(em[k-tLen:k-hashLen], prefix) > + copy(em[k-hashLen:k], hashed) > + > +- m := new(big.Int).SetBytes(em) > +- c, err := decryptAndCheck(rand, priv, m) > +- if err != nil { > +- return nil, err > +- } > +- > +- return c.FillBytes(em), nil > ++ return decryptAndCheck(priv, em) > + } > + > + // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature. > +@@ -275,9 +262,7 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, > hashed []byte, sig []byte) > + return ErrVerification > + } > + > +- c := new(big.Int).SetBytes(sig) > +- m := encrypt(new(big.Int), pub, c) > +- em := m.FillBytes(make([]byte, k)) > ++ em := encrypt(pub, sig) > + // EM = 0x00 || 0x01 || PS || 0x00 || T > + > + ok := subtle.ConstantTimeByteEq(em[0], 0) > +diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go > +index 814522d..eaba4be 100644 > +--- a/src/crypto/rsa/pss.go > ++++ b/src/crypto/rsa/pss.go > +@@ -12,7 +12,6 @@ import ( > + "errors" > + "hash" > + "io" > +- "math/big" > + ) > + > + // Per RFC 8017, Section 9.1 > +@@ -207,19 +206,27 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, > hash hash.Hash) error { > + // Note that hashed must be the result of hashing the input message using > the > + // given hash function. salt is a random sequence of bytes whose length > will be > + // later used to verify the signature. > +-func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, > hashed, salt []byte) ([]byte, error) { > +- emBits := priv.N.BitLen() - 1 > ++func signPSSWithSalt(priv *PrivateKey, hash crypto.Hash, hashed, salt > []byte) ([]byte, error) { > ++ emBits := bigBitLen(priv.N) - 1 > + em, err := emsaPSSEncode(hashed, emBits, salt, hash.New()) > + if err != nil { > + return nil, err > + } > +- m := new(big.Int).SetBytes(em) > +- c, err := decryptAndCheck(rand, priv, m) > +- if err != nil { > +- return nil, err > ++ > ++ // RFC 8017: "Note that the octet length of EM will be one less than > k if > ++ // modBits - 1 is divisible by 8 and equal to k otherwise, where k is > the > ++ // length in octets of the RSA modulus n." 🙄 > ++ // > ++ // This is extremely annoying, as all other encrypt and decrypt > inputs are > ++ // always the exact same size as the modulus. Since it only happens > for > ++ // weird modulus sizes, fix it by padding inefficiently. > ++ if emLen, k := len(em), priv.Size(); emLen < k { > ++ emNew := make([]byte, k) > ++ copy(emNew[k-emLen:], em) > ++ em = emNew > + } > +- s := make([]byte, priv.Size()) > +- return c.FillBytes(s), nil > ++ > ++ return decryptAndCheck(priv, em) > + } > + > + const ( > +@@ -269,7 +276,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash > crypto.Hash, digest []byte, > + saltLength := opts.saltLength() > + switch saltLength { > + case PSSSaltLengthAuto: > +- saltLength = (priv.N.BitLen()-1+7)/8 - 2 - hash.Size() > ++ saltLength = (bigBitLen(priv.N)-1+7)/8 - 2 - hash.Size() > + case PSSSaltLengthEqualsHash: > + saltLength = hash.Size() > + } > +@@ -278,7 +285,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash > crypto.Hash, digest []byte, > + if _, err := io.ReadFull(rand, salt); err != nil { > + return nil, err > + } > +- return signPSSWithSalt(rand, priv, hash, digest, salt) > ++ return signPSSWithSalt(priv, hash, digest, salt) > + } > + > + // VerifyPSS verifies a PSS signature. > +@@ -291,13 +298,22 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, > digest []byte, sig []byte, opts > + if len(sig) != pub.Size() { > + return ErrVerification > + } > +- s := new(big.Int).SetBytes(sig) > +- m := encrypt(new(big.Int), pub, s) > +- emBits := pub.N.BitLen() - 1 > ++ > ++ emBits := bigBitLen(pub.N) - 1 > + emLen := (emBits + 7) / 8 > +- if m.BitLen() > emLen*8 { > +- return ErrVerification > ++ em := encrypt(pub, sig) > ++ > ++ // Like in signPSSWithSalt, deal with mismatches between emLen and > the size > ++ // of the modulus. The spec would have us wire emLen into the encoding > ++ // function, but we'd rather always encode to the size of the modulus > and > ++ // then strip leading zeroes if necessary. This only happens for weird > ++ // modulus sizes anyway. > ++ for len(em) > emLen && len(em) > 0 { > ++ if em[0] != 0 { > ++ return ErrVerification > ++ } > ++ em = em[1:] > + } > +- em := m.FillBytes(make([]byte, emLen)) > ++ > + return emsaPSSVerify(digest, em, emBits, opts.saltLength(), > hash.New()) > + } > +diff --git a/src/crypto/rsa/pss_test.go b/src/crypto/rsa/pss_test.go > +index c3a6d46..d018b43 100644 > +--- a/src/crypto/rsa/pss_test.go > ++++ b/src/crypto/rsa/pss_test.go > +@@ -233,7 +233,10 @@ func TestPSSSigning(t *testing.T) { > + } > + } > + > +-func TestSignWithPSSSaltLengthAuto(t *testing.T) { > ++func TestPSS513(t *testing.T) { > ++ // See Issue 42741, and separately, RFC 8017: "Note that the octet > length of > ++ // EM will be one less than k if modBits - 1 is divisible by 8 and > equal to > ++ // k otherwise, where k is the length in octets of the RSA modulus n." > + key, err := GenerateKey(rand.Reader, 513) > + if err != nil { > + t.Fatal(err) > +@@ -246,8 +249,9 @@ func TestSignWithPSSSaltLengthAuto(t *testing.T) { > + if err != nil { > + t.Fatal(err) > + } > +- if len(signature) == 0 { > +- t.Fatal("empty signature returned") > ++ err = VerifyPSS(&key.PublicKey, crypto.SHA256, digest[:], signature, > nil) > ++ if err != nil { > ++ t.Error(err) > + } > + } > + > +diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go > +index 5a00ed2..29d9d31 100644 > +--- a/src/crypto/rsa/rsa.go > ++++ b/src/crypto/rsa/rsa.go > +@@ -19,13 +19,17 @@ > + // over the public key primitive, the PrivateKey type implements the > + // Decrypter and Signer interfaces from the crypto package. > + // > +-// The RSA operations in this package are not implemented using > constant-time algorithms. > ++// Operations in this package are implemented using constant-time > algorithms, > ++// except for [GenerateKey], [PrivateKey.Precompute], and > [PrivateKey.Validate]. > ++// Every other operation only leaks the bit size of the involved values, > which > ++// all depend on the selected key size. > + package rsa > + > + import ( > + "crypto" > + "crypto/rand" > + "crypto/subtle" > ++ "encoding/binary" > + "errors" > + "hash" > + "io" > +@@ -35,7 +39,6 @@ import ( > + "crypto/internal/randutil" > + ) > + > +-var bigZero = big.NewInt(0) > + var bigOne = big.NewInt(1) > + > + // A PublicKey represents the public part of an RSA key. > +@@ -47,7 +50,7 @@ type PublicKey struct { > + // Size returns the modulus size in bytes. Raw signatures and ciphertexts > + // for or by this public key will have the same size. > + func (pub *PublicKey) Size() int { > +- return (pub.N.BitLen() + 7) / 8 > ++ return (bigBitLen(pub.N) + 7) / 8 > + } > + > + // OAEPOptions is an interface for passing options to OAEP decryption using > the > +@@ -351,10 +354,19 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { > + // too large for the size of the public key. > + var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA > public key size") > + > +-func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int { > +- e := big.NewInt(int64(pub.E)) > +- c.Exp(m, e, pub.N) > +- return c > ++func encrypt(pub *PublicKey, plaintext []byte) []byte { > ++ > ++ N := modulusFromNat(natFromBig(pub.N)) > ++ m := natFromBytes(plaintext).expandFor(N) > ++ > ++ e := make([]byte, 8) > ++ binary.BigEndian.PutUint64(e, uint64(pub.E)) > ++ for len(e) > 1 && e[0] == 0 { > ++ e = e[1:] > ++ } > ++ > ++ out := make([]byte, modulusSize(N)) > ++ return new(nat).exp(m, e, N).fillBytes(out) > + } > + > + // EncryptOAEP encrypts the given message with RSA-OAEP. > +@@ -404,12 +416,7 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub > *PublicKey, msg []byte, l > + mgf1XOR(db, hash, seed) > + mgf1XOR(seed, hash, db) > + > +- m := new(big.Int) > +- m.SetBytes(em) > +- c := encrypt(new(big.Int), pub, m) > +- > +- out := make([]byte, k) > +- return c.FillBytes(out), nil > ++ return encrypt(pub, em), nil > + } > + > + // ErrDecryption represents a failure to decrypt a message. > +@@ -451,98 +458,71 @@ func (priv *PrivateKey) Precompute() { > + } > + } > + > +-// decrypt performs an RSA decryption, resulting in a plaintext integer. If > a > +-// random source is given, RSA blinding is used. > +-func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, > err error) { > +- // TODO(agl): can we get away with reusing blinds? > +- if c.Cmp(priv.N) > 0 { > +- err = ErrDecryption > +- return > ++// decrypt performs an RSA decryption of ciphertext into out. > ++func decrypt(priv *PrivateKey, ciphertext []byte) ([]byte, error) { > ++ > ++ N := modulusFromNat(natFromBig(priv.N)) > ++ c := natFromBytes(ciphertext).expandFor(N) > ++ if c.cmpGeq(N.nat) == 1 { > ++ return nil, ErrDecryption > + } > + if priv.N.Sign() == 0 { > + return nil, ErrDecryption > + } > + > +- var ir *big.Int > +- if random != nil { > +- randutil.MaybeReadByte(random) > +- > +- // Blinding enabled. Blinding involves multiplying c by r^e. > +- // Then the decryption operation performs (m^e * r^e)^d mod n > +- // which equals mr mod n. The factor of r can then be removed > +- // by multiplying by the multiplicative inverse of r. > +- > +- var r *big.Int > +- ir = new(big.Int) > +- for { > +- r, err = rand.Int(random, priv.N) > +- if err != nil { > +- return > +- } > +- if r.Cmp(bigZero) == 0 { > +- r = bigOne > +- } > +- ok := ir.ModInverse(r, priv.N) > +- if ok != nil { > +- break > +- } > +- } > +- bigE := big.NewInt(int64(priv.E)) > +- rpowe := new(big.Int).Exp(r, bigE, priv.N) // N != 0 > +- cCopy := new(big.Int).Set(c) > +- cCopy.Mul(cCopy, rpowe) > +- cCopy.Mod(cCopy, priv.N) > +- c = cCopy > +- } > +- > ++ // Note that because our private decryption exponents are stored as > big.Int, > ++ // we potentially leak the exact number of bits of these exponents. > This > ++ // isn't great, but should be fine. > + if priv.Precomputed.Dp == nil { > +- m = new(big.Int).Exp(c, priv.D, priv.N) > +- } else { > +- // We have the precalculated values needed for the CRT. > +- m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0]) > +- m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1]) > +- m.Sub(m, m2) > +- if m.Sign() < 0 { > +- m.Add(m, priv.Primes[0]) > +- } > +- m.Mul(m, priv.Precomputed.Qinv) > +- m.Mod(m, priv.Primes[0]) > +- m.Mul(m, priv.Primes[1]) > +- m.Add(m, m2) > +- > +- for i, values := range priv.Precomputed.CRTValues { > +- prime := priv.Primes[2+i] > +- m2.Exp(c, values.Exp, prime) > +- m2.Sub(m2, m) > +- m2.Mul(m2, values.Coeff) > +- m2.Mod(m2, prime) > +- if m2.Sign() < 0 { > +- m2.Add(m2, prime) > +- } > +- m2.Mul(m2, values.R) > +- m.Add(m, m2) > +- } > +- } > +- > +- if ir != nil { > +- // Unblind. > +- m.Mul(m, ir) > +- m.Mod(m, priv.N) > +- } > +- > +- return > ++ out := make([]byte, modulusSize(N)) > ++ return new(nat).exp(c, priv.D.Bytes(), N).fillBytes(out), nil > ++ } > ++ > ++ t0 := new(nat) > ++ P := modulusFromNat(natFromBig(priv.Primes[0])) > ++ Q := modulusFromNat(natFromBig(priv.Primes[1])) > ++ // m = c ^ Dp mod p > ++ m := new(nat).exp(t0.mod(c, P), priv.Precomputed.Dp.Bytes(), P) > ++ // m2 = c ^ Dq mod q > ++ m2 := new(nat).exp(t0.mod(c, Q), priv.Precomputed.Dq.Bytes(), Q) > ++ // m = m - m2 mod p > ++ m.modSub(t0.mod(m2, P), P) > ++ // m = m * Qinv mod p > ++ m.modMul(natFromBig(priv.Precomputed.Qinv).expandFor(P), P) > ++ // m = m * q mod N > ++ m.expandFor(N).modMul(t0.mod(Q.nat, N), N) > ++ // m = m + m2 mod N > ++ m.modAdd(m2.expandFor(N), N) > ++ > ++ for i, values := range priv.Precomputed.CRTValues { > ++ p := modulusFromNat(natFromBig(priv.Primes[2+i])) > ++ // m2 = c ^ Exp mod p > ++ m2.exp(t0.mod(c, p), values.Exp.Bytes(), p) > ++ // m2 = m2 - m mod p > ++ m2.modSub(t0.mod(m, p), p) > ++ // m2 = m2 * Coeff mod p > ++ m2.modMul(natFromBig(values.Coeff).expandFor(p), p) > ++ // m2 = m2 * R mod N > ++ R := natFromBig(values.R).expandFor(N) > ++ m2.expandFor(N).modMul(R, N) > ++ // m = m + m2 mod N > ++ m.modAdd(m2, N) > ++ } > ++ > ++ out := make([]byte, modulusSize(N)) > ++ return m.fillBytes(out), nil > + } > + > +-func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m > *big.Int, err error) { > +- m, err = decrypt(random, priv, c) > ++func decryptAndCheck(priv *PrivateKey, ciphertext []byte) (m []byte, err > error) { > ++ m, err = decrypt(priv, ciphertext) > + if err != nil { > + return nil, err > + } > + > + // In order to defend against errors in the CRT computation, m^e is > + // calculated, which should match the original ciphertext. > +- check := encrypt(new(big.Int), &priv.PublicKey, m) > +- if c.Cmp(check) != 0 { > ++ check := encrypt(&priv.PublicKey, m) > ++ if subtle.ConstantTimeCompare(ciphertext, check) != 1 { > + return nil, errors.New("rsa: internal error") > + } > + return m, nil > +@@ -554,9 +534,7 @@ func decryptAndCheck(random io.Reader, priv *PrivateKey, > c *big.Int) (m *big.Int > + // Encryption and decryption of a given message must use the same hash > function > + // and sha256.New() is a reasonable choice. > + // > +-// The random parameter, if not nil, is used to blind the private-key > operation > +-// and avoid timing side-channel attacks. Blinding is purely internal to > this > +-// function – the random data need not match that used when encrypting. > ++// The random parameter is legacy and ignored, and it can be as nil. > + // > + // The label parameter must match the value given when encrypting. See > + // EncryptOAEP for details. > +@@ -570,9 +548,7 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv > *PrivateKey, ciphertext > + return nil, ErrDecryption > + } > + > +- c := new(big.Int).SetBytes(ciphertext) > +- > +- m, err := decrypt(random, priv, c) > ++ em, err := decrypt(priv, ciphertext) > + if err != nil { > + return nil, err > + } > +@@ -581,10 +557,6 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv > *PrivateKey, ciphertext > + lHash := hash.Sum(nil) > + hash.Reset() > + > +- // We probably leak the number of leading zeros. > +- // It's not clear that we can do anything about this. > +- em := m.FillBytes(make([]byte, k)) > +- > + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) > + > + seed := em[1 : hash.Size()+1] > +-- > +2.25.1 > + > -- > 2.25.1 > > > >
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#193359): https://lists.openembedded.org/g/openembedded-core/message/193359 Mute This Topic: https://lists.openembedded.org/mt/103539124/21656 Group Owner: openembedded-core+ow...@lists.openembedded.org Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-