mirror of
https://github.com/golang/go.git
synced 2026-06-28 03:40:37 +00:00
crypto/internal/fips140/rsa: add large exponent support for ACVP tests
Change-Id: I6ddf1e2af4f2d139e54821f10b99d9de6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/738160 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
3cdb042b2e
commit
44fde0fd08
1 changed files with 115 additions and 0 deletions
115
src/crypto/internal/fips140/rsa/largeexponent.go
Normal file
115
src/crypto/internal/fips140/rsa/largeexponent.go
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2026 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"
|
||||
"crypto/internal/fips140"
|
||||
"crypto/internal/fips140/bigmod"
|
||||
"errors"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// TestingOnlyLargeExponentPublicKey is a variant of [PublicKey] that supports
|
||||
// large public exponents. It is only meant for supporting the full ACVP test
|
||||
// suite, which unfortunately forces us to choose between a fixed exponent and
|
||||
// the full (2¹⁶, 2²⁵⁶) range. This type must not be used in production code,
|
||||
// nor for e values < 2³¹, which instead must use [PublicKey].
|
||||
type TestingOnlyLargeExponentPublicKey struct {
|
||||
N *bigmod.Modulus
|
||||
// E is the public exponent, represented as a big-endian byte slice.
|
||||
E []byte
|
||||
}
|
||||
|
||||
func (pub *TestingOnlyLargeExponentPublicKey) Size() int {
|
||||
return (pub.N.BitLen() + 7) / 8
|
||||
}
|
||||
|
||||
func checkLargeExponentPublicKey(pub *TestingOnlyLargeExponentPublicKey) error {
|
||||
if pub.N == nil {
|
||||
return errors.New("crypto/rsa: missing public modulus")
|
||||
}
|
||||
if pub.N.Nat().IsOdd() == 0 {
|
||||
return errors.New("crypto/rsa: public modulus is even")
|
||||
}
|
||||
if pub.N.BitLen() < 2048 {
|
||||
return errors.New("crypto/rsa: public modulus too small")
|
||||
}
|
||||
if pub.N.BitLen()%2 == 1 {
|
||||
return errors.New("crypto/rsa: public modulus bit length not even")
|
||||
}
|
||||
E := pub.E
|
||||
for len(E) > 0 && E[0] == 0 {
|
||||
E = E[1:]
|
||||
}
|
||||
if len(E) < 32/8 || (len(E) == 32/8 && E[0] < 0x80) {
|
||||
// Exponents less than 2^31 must use [PublicKey].
|
||||
return errors.New("crypto/rsa: public exponent too small")
|
||||
}
|
||||
if len(E) > 256/8 {
|
||||
return errors.New("crypto/rsa: public exponent too large")
|
||||
}
|
||||
if E[len(E)-1]&1 == 0 {
|
||||
return errors.New("crypto/rsa: public exponent is even")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encryptLargeExponent(pub *TestingOnlyLargeExponentPublicKey, plaintext []byte) ([]byte, error) {
|
||||
m, err := bigmod.NewNat().SetBytes(plaintext, pub.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bigmod.NewNat().Exp(m, pub.E, pub.N).Bytes(pub.N), nil
|
||||
}
|
||||
|
||||
func TestingOnlyLargeExponentVerifyPKCS1v15(pub *TestingOnlyLargeExponentPublicKey, hash string, hashed []byte, sig []byte) error {
|
||||
fipsSelfTest()
|
||||
fips140.RecordApproved()
|
||||
checkApprovedHashName(hash)
|
||||
if err := checkLargeExponentPublicKey(pub); err != nil {
|
||||
return err
|
||||
}
|
||||
if pub.Size() != len(sig) {
|
||||
return ErrVerification
|
||||
}
|
||||
em, err := encryptLargeExponent(pub, sig)
|
||||
if err != nil {
|
||||
return ErrVerification
|
||||
}
|
||||
expected, err := pkcs1v15ConstructEM(&PublicKey{N: pub.N}, hash, hashed)
|
||||
if err != nil {
|
||||
return ErrVerification
|
||||
}
|
||||
if !bytes.Equal(em, expected) {
|
||||
return ErrVerification
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestingOnlyLargeExponentVerifyPSS(pub *TestingOnlyLargeExponentPublicKey, hash hash.Hash, digest []byte, sig []byte) error {
|
||||
fipsSelfTest()
|
||||
fips140.RecordApproved()
|
||||
checkApprovedHash(hash)
|
||||
if err := checkLargeExponentPublicKey(pub); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(sig) != pub.Size() {
|
||||
return ErrVerification
|
||||
}
|
||||
emBits := pub.N.BitLen() - 1
|
||||
emLen := (emBits + 7) / 8
|
||||
em, err := encryptLargeExponent(pub, sig)
|
||||
if err != nil {
|
||||
return ErrVerification
|
||||
}
|
||||
for len(em) > emLen && len(em) > 0 {
|
||||
if em[0] != 0 {
|
||||
return ErrVerification
|
||||
}
|
||||
em = em[1:]
|
||||
}
|
||||
return emsaPSSVerify(digest, em, emBits, pssSaltLengthAutodetect, hash)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue