github.com/cloudflare/circl@v1.5.0/tss/rsa/internal/pss/pss.go (about)

     1  // https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/crypto/rsa/pss.go
     2  
     3  // Copyright (c) 2009 The Go Authors. All rights reserved.
     4  //
     5  // Redistribution and use in source and binary forms, with or without
     6  // modification, are permitted provided that the following conditions are
     7  // met:
     8  //
     9  //    * Redistributions of source code must retain the above copyright
    10  // notice, this list of conditions and the following disclaimer.
    11  //    * Redistributions in binary form must reproduce the above
    12  // copyright notice, this list of conditions and the following disclaimer
    13  // in the documentation and/or other materials provided with the
    14  // distribution.
    15  //    * Neither the name of Google Inc. nor the names of its
    16  // contributors may be used to endorse or promote products derived from
    17  // this software without specific prior written permission.
    18  //
    19  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    20  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    21  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    22  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    23  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    24  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    25  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    26  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    27  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    28  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    29  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    30  
    31  // Copyright 2013 The Go Authors. All rights reserved.
    32  // Use of this source code is governed by a BSD-style
    33  // license that can be found in the LICENSE file.
    34  
    35  package pss
    36  
    37  // This file implements the RSASSA-PSS signature scheme according to RFC 8017.
    38  
    39  import (
    40  	"crypto"
    41  	"crypto/rsa"
    42  	"errors"
    43  	"hash"
    44  	"io"
    45  )
    46  
    47  // Per RFC 8017, Section 9.1
    48  //
    49  //     EM = MGF1 xor DB || H( 8*0x00 || mHash || salt ) || 0xbc
    50  //
    51  // where
    52  //
    53  //     DB = PS || 0x01 || salt
    54  //
    55  // and PS can be empty so
    56  //
    57  //     emLen = dbLen + hLen + 1 = psLen + sLen + hLen + 2
    58  //
    59  
    60  func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) {
    61  	// See RFC 8017, Section 9.1.1.
    62  
    63  	hLen := hash.Size()
    64  	sLen := len(salt)
    65  	emLen := (emBits + 7) / 8
    66  
    67  	// 1.  If the length of M is greater than the input limitation for the
    68  	//     hash function (2^61 - 1 octets for SHA-1), output "message too
    69  	//     long" and stop.
    70  	//
    71  	// 2.  Let mHash = Hash(M), an octet string of length hLen.
    72  
    73  	if len(mHash) != hLen {
    74  		return nil, errors.New("crypto/rsa: input must be hashed with given hash")
    75  	}
    76  
    77  	// 3.  If emLen < hLen + sLen + 2, output "encoding error" and stop.
    78  
    79  	if emLen < hLen+sLen+2 {
    80  		return nil, errors.New("crypto/rsa: key size too small for PSS signature")
    81  	}
    82  
    83  	em := make([]byte, emLen)
    84  	psLen := emLen - sLen - hLen - 2
    85  	db := em[:psLen+1+sLen]
    86  	h := em[psLen+1+sLen : emLen-1]
    87  
    88  	// 4.  Generate a random octet string salt of length sLen; if sLen = 0,
    89  	//     then salt is the empty string.
    90  	//
    91  	// 5.  Let
    92  	//       M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt;
    93  	//
    94  	//     M' is an octet string of length 8 + hLen + sLen with eight
    95  	//     initial zero octets.
    96  	//
    97  	// 6.  Let H = Hash(M'), an octet string of length hLen.
    98  
    99  	var prefix [8]byte
   100  
   101  	hash.Write(prefix[:])
   102  	hash.Write(mHash)
   103  	hash.Write(salt)
   104  
   105  	h = hash.Sum(h[:0])
   106  	hash.Reset()
   107  
   108  	// 7.  Generate an octet string PS consisting of emLen - sLen - hLen - 2
   109  	//     zero octets. The length of PS may be 0.
   110  	//
   111  	// 8.  Let DB = PS || 0x01 || salt; DB is an octet string of length
   112  	//     emLen - hLen - 1.
   113  
   114  	db[psLen] = 0x01
   115  	copy(db[psLen+1:], salt)
   116  
   117  	// 9.  Let dbMask = MGF(H, emLen - hLen - 1).
   118  	//
   119  	// 10. Let maskedDB = DB \xor dbMask.
   120  
   121  	mgf1XOR(db, hash, h)
   122  
   123  	// 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in
   124  	//     maskedDB to zero.
   125  
   126  	db[0] &= 0xff >> (8*emLen - emBits)
   127  
   128  	// 12. Let EM = maskedDB || H || 0xbc.
   129  	em[emLen-1] = 0xbc
   130  
   131  	// 13. Output EM.
   132  	return em, nil
   133  }
   134  
   135  func padPSSWithSalt(pub *rsa.PublicKey, hash crypto.Hash, hashed, salt []byte) ([]byte, error) {
   136  	emBits := pub.N.BitLen() - 1
   137  	em, err := emsaPSSEncode(hashed, emBits, salt, hash.New())
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	return em, nil
   142  }
   143  
   144  func saltLength(opts *rsa.PSSOptions) int {
   145  	if opts == nil {
   146  		return rsa.PSSSaltLengthAuto
   147  	}
   148  	return opts.SaltLength
   149  }
   150  
   151  func PadPSS(rand io.Reader, pub *rsa.PublicKey, hash crypto.Hash, digest []byte, opts *rsa.PSSOptions) ([]byte, error) {
   152  	if opts != nil && opts.Hash != 0 {
   153  		hash = opts.Hash
   154  	}
   155  
   156  	saltLength := saltLength(opts)
   157  	switch saltLength {
   158  	case rsa.PSSSaltLengthAuto:
   159  		saltLength = (pub.N.BitLen()-1+7)/8 - 2 - hash.Size()
   160  	case rsa.PSSSaltLengthEqualsHash:
   161  		saltLength = hash.Size()
   162  	}
   163  
   164  	salt := make([]byte, saltLength)
   165  	if _, err := io.ReadFull(rand, salt); err != nil {
   166  		return nil, err
   167  	}
   168  	return padPSSWithSalt(pub, hash, digest, salt)
   169  }