github.com/cloudflare/circl@v1.5.0/blindsign/blindrsa/internal/common/pss.go (about)

     1  // Copyright (c) 2009 The Go Authors. All rights reserved.
     2  //
     3  // Redistribution and use in source and binary forms, with or without
     4  // modification, are permitted provided that the following conditions are
     5  // met:
     6  //
     7  //    * Redistributions of source code must retain the above copyright
     8  // notice, this list of conditions and the following disclaimer.
     9  //    * Redistributions in binary form must reproduce the above
    10  // copyright notice, this list of conditions and the following disclaimer
    11  // in the documentation and/or other materials provided with the
    12  // distribution.
    13  //    * Neither the name of Google Inc. nor the names of its
    14  // contributors may be used to endorse or promote products derived from
    15  // this software without specific prior written permission.
    16  //
    17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    28  
    29  package common
    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  // This file implements the RSASSA-PSS signature scheme according to RFC 8017.
    36  
    37  import (
    38  	"bytes"
    39  	"crypto/rsa"
    40  	"errors"
    41  	"hash"
    42  )
    43  
    44  // Per RFC 8017, Section 9.1
    45  //
    46  //     EM = MGF1 xor DB || H( 8*0x00 || mHash || salt ) || 0xbc
    47  //
    48  // where
    49  //
    50  //     DB = PS || 0x01 || salt
    51  //
    52  // and PS can be empty so
    53  //
    54  //     emLen = dbLen + hLen + 1 = psLen + sLen + hLen + 2
    55  //
    56  
    57  func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) {
    58  	// See RFC 8017, Section 9.1.1.
    59  
    60  	hLen := hash.Size()
    61  	sLen := len(salt)
    62  	emLen := (emBits + 7) / 8
    63  
    64  	// 1.  If the length of M is greater than the input limitation for the
    65  	//     hash function (2^61 - 1 octets for SHA-1), output "message too
    66  	//     long" and stop.
    67  	//
    68  	// 2.  Let mHash = Hash(M), an octet string of length hLen.
    69  
    70  	if len(mHash) != hLen {
    71  		return nil, errors.New("crypto/rsa: input must be hashed with given hash")
    72  	}
    73  
    74  	// 3.  If emLen < hLen + sLen + 2, output "encoding error" and stop.
    75  
    76  	if emLen < hLen+sLen+2 {
    77  		return nil, errors.New("crypto/rsa: key size too small for PSS signature")
    78  	}
    79  
    80  	em := make([]byte, emLen)
    81  	psLen := emLen - sLen - hLen - 2
    82  	db := em[:psLen+1+sLen]
    83  	h := em[psLen+1+sLen : emLen-1]
    84  
    85  	// 4.  Generate a random octet string salt of length sLen; if sLen = 0,
    86  	//     then salt is the empty string.
    87  	//
    88  	// 5.  Let
    89  	//       M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt;
    90  	//
    91  	//     M' is an octet string of length 8 + hLen + sLen with eight
    92  	//     initial zero octets.
    93  	//
    94  	// 6.  Let H = Hash(M'), an octet string of length hLen.
    95  
    96  	var prefix [8]byte
    97  
    98  	hash.Write(prefix[:])
    99  	hash.Write(mHash)
   100  	hash.Write(salt)
   101  
   102  	h = hash.Sum(h[:0])
   103  	hash.Reset()
   104  
   105  	// 7.  Generate an octet string PS consisting of emLen - sLen - hLen - 2
   106  	//     zero octets. The length of PS may be 0.
   107  	//
   108  	// 8.  Let DB = PS || 0x01 || salt; DB is an octet string of length
   109  	//     emLen - hLen - 1.
   110  
   111  	db[psLen] = 0x01
   112  	copy(db[psLen+1:], salt)
   113  
   114  	// 9.  Let dbMask = MGF(H, emLen - hLen - 1).
   115  	//
   116  	// 10. Let maskedDB = DB \xor dbMask.
   117  
   118  	mgf1XOR(db, hash, h)
   119  
   120  	// 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in
   121  	//     maskedDB to zero.
   122  
   123  	db[0] &= 0xff >> (8*emLen - emBits)
   124  
   125  	// 12. Let EM = maskedDB || H || 0xbc.
   126  	em[emLen-1] = 0xbc
   127  
   128  	// 13. Output EM.
   129  	return em, nil
   130  }
   131  
   132  func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error {
   133  	// See RFC 8017, Section 9.1.2.
   134  
   135  	hLen := hash.Size()
   136  	if sLen == rsa.PSSSaltLengthEqualsHash {
   137  		sLen = hLen
   138  	}
   139  	emLen := (emBits + 7) / 8
   140  	if emLen != len(em) {
   141  		return errors.New("rsa: internal error: inconsistent length")
   142  	}
   143  
   144  	// 1.  If the length of M is greater than the input limitation for the
   145  	//     hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
   146  	//     and stop.
   147  	//
   148  	// 2.  Let mHash = Hash(M), an octet string of length hLen.
   149  	if hLen != len(mHash) {
   150  		return rsa.ErrVerification
   151  	}
   152  
   153  	// 3.  If emLen < hLen + sLen + 2, output "inconsistent" and stop.
   154  	if emLen < hLen+sLen+2 {
   155  		return rsa.ErrVerification
   156  	}
   157  
   158  	// 4.  If the rightmost octet of EM does not have hexadecimal value
   159  	//     0xbc, output "inconsistent" and stop.
   160  	if em[emLen-1] != 0xbc {
   161  		return rsa.ErrVerification
   162  	}
   163  
   164  	// 5.  Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
   165  	//     let H be the next hLen octets.
   166  	db := em[:emLen-hLen-1]
   167  	h := em[emLen-hLen-1 : emLen-1]
   168  
   169  	// 6.  If the leftmost 8 * emLen - emBits bits of the leftmost octet in
   170  	//     maskedDB are not all equal to zero, output "inconsistent" and
   171  	//     stop.
   172  	var bitMask byte = 0xff >> (8*emLen - emBits)
   173  	if em[0] & ^bitMask != 0 {
   174  		return rsa.ErrVerification
   175  	}
   176  
   177  	// 7.  Let dbMask = MGF(H, emLen - hLen - 1).
   178  	//
   179  	// 8.  Let DB = maskedDB \xor dbMask.
   180  	mgf1XOR(db, hash, h)
   181  
   182  	// 9.  Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
   183  	//     to zero.
   184  	db[0] &= bitMask
   185  
   186  	// If we don't know the salt length, look for the 0x01 delimiter.
   187  	if sLen == rsa.PSSSaltLengthAuto {
   188  		psLen := bytes.IndexByte(db, 0x01)
   189  		if psLen < 0 {
   190  			return rsa.ErrVerification
   191  		}
   192  		sLen = len(db) - psLen - 1
   193  	}
   194  
   195  	// 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
   196  	//     or if the octet at position emLen - hLen - sLen - 1 (the leftmost
   197  	//     position is "position 1") does not have hexadecimal value 0x01,
   198  	//     output "inconsistent" and stop.
   199  	psLen := emLen - hLen - sLen - 2
   200  	for _, e := range db[:psLen] {
   201  		if e != 0x00 {
   202  			return rsa.ErrVerification
   203  		}
   204  	}
   205  	if db[psLen] != 0x01 {
   206  		return rsa.ErrVerification
   207  	}
   208  
   209  	// 11.  Let salt be the last sLen octets of DB.
   210  	salt := db[len(db)-sLen:]
   211  
   212  	// 12.  Let
   213  	//          M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
   214  	//     M' is an octet string of length 8 + hLen + sLen with eight
   215  	//     initial zero octets.
   216  	//
   217  	// 13. Let H' = Hash(M'), an octet string of length hLen.
   218  	var prefix [8]byte
   219  	hash.Write(prefix[:])
   220  	hash.Write(mHash)
   221  	hash.Write(salt)
   222  
   223  	h0 := hash.Sum(nil)
   224  
   225  	// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
   226  	if !bytes.Equal(h0, h) { // TODO: constant time?
   227  		return rsa.ErrVerification
   228  	}
   229  	return nil
   230  }