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 }