Source File
pss.go
Belonging Package
crypto/rsa
// Copyright 2013 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// This file implements the RSASSA-PSS signature scheme according to RFC 8017.import ()// 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 ( []byte, int, []byte, hash.Hash) ([]byte, error) {// See RFC 8017, Section 9.1.1.:= .Size():= len():= ( + 7) / 8// 1. If the length of M is greater than the input limitation for the// hash function (2^61 - 1 octets for SHA-1), output "message too// long" and stop.//// 2. Let mHash = Hash(M), an octet string of length hLen.if len() != {return nil, errors.New("crypto/rsa: input must be hashed with given hash")}// 3. If emLen < hLen + sLen + 2, output "encoding error" and stop.if < ++2 {return nil, ErrMessageTooLong}:= make([]byte, ):= - - - 2:= [:+1+]:= [+1+ : -1]// 4. Generate a random octet string salt of length sLen; if sLen = 0,// then salt is the empty string.//// 5. Let// M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt;//// M' is an octet string of length 8 + hLen + sLen with eight// initial zero octets.//// 6. Let H = Hash(M'), an octet string of length hLen.var [8]byte.Write([:]).Write().Write()= .Sum([:0]).Reset()// 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2// zero octets. The length of PS may be 0.//// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length// emLen - hLen - 1.[] = 0x01copy([+1:], )// 9. Let dbMask = MGF(H, emLen - hLen - 1).//// 10. Let maskedDB = DB \xor dbMask.mgf1XOR(, , )// 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in// maskedDB to zero.[0] &= 0xff >> (8* - )// 12. Let EM = maskedDB || H || 0xbc.[-1] = 0xbc// 13. Output EM.return , nil}func (, []byte, , int, hash.Hash) error {// See RFC 8017, Section 9.1.2.:= .Size()if == PSSSaltLengthEqualsHash {=}:= ( + 7) / 8if != len() {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.if != len() {return ErrVerification}// 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.if < ++2 {return ErrVerification}// 4. If the rightmost octet of EM does not have hexadecimal value// 0xbc, output "inconsistent" and stop.if [-1] != 0xbc {return ErrVerification}// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and// let H be the next hLen octets.:= [:--1]:= [--1 : -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.var byte = 0xff >> (8* - )if [0] & ^ != 0 {return ErrVerification}// 7. Let dbMask = MGF(H, emLen - hLen - 1).//// 8. Let DB = maskedDB \xor dbMask.mgf1XOR(, , )// 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB// to zero.[0] &=// If we don't know the salt length, look for the 0x01 delimiter.if == PSSSaltLengthAuto {:= bytes.IndexByte(, 0x01)if < 0 {return ErrVerification}= len() - - 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.:= - - - 2for , := range [:] {if != 0x00 {return ErrVerification}}if [] != 0x01 {return ErrVerification}// 11. Let salt be the last sLen octets of DB.:= [len()-:]// 12. Let// M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;// M' is an octet string of length 8 + hLen + sLen with eight// initial zero octets.//// 13. Let H' = Hash(M'), an octet string of length hLen.var [8]byte.Write([:]).Write().Write():= .Sum(nil)// 14. If H = H', output "consistent." Otherwise, output "inconsistent."if !bytes.Equal(, ) { // TODO: constant time?return ErrVerification}return nil}// 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 ( *PrivateKey, crypto.Hash, , []byte) ([]byte, error) {:= .N.BitLen() - 1, := emsaPSSEncode(, , , .New())if != nil {return nil,}if boring.Enabled {, := boringPrivateKey()if != nil {return nil,}// Note: BoringCrypto always does decrypt "withCheck".// (It's not just decrypt.), := boring.DecryptRSANoPadding(, )if != nil {return nil,}return , nil}// 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 , := len(), .Size(); < {:= make([]byte, )copy([-:], )=}return decrypt(, , withCheck)}const (// PSSSaltLengthAuto causes the salt in a PSS signature to be as large// as possible when signing, and to be auto-detected when verifying.PSSSaltLengthAuto = 0// PSSSaltLengthEqualsHash causes the salt length to equal the length// of the hash used in the signature.PSSSaltLengthEqualsHash = -1)// PSSOptions contains options for creating and verifying PSS signatures.type PSSOptions struct {// SaltLength controls the length of the salt used in the PSS signature. It// can either be a positive number of bytes, or one of the special// PSSSaltLength constants.SaltLength int// 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 opts.Hash so that [PSSOptions] implements [crypto.SignerOpts].func ( *PSSOptions) () crypto.Hash {return .Hash}func ( *PSSOptions) () int {if == nil {return PSSSaltLengthAuto}return .SaltLength}var invalidSaltLenErr = errors.New("crypto/rsa: PSSOptions.SaltLength cannot be negative")// 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.//// The signature is randomized depending on the message, key, and salt size,// using bytes from rand. Most applications should use [crypto/rand.Reader] as// rand.func ( io.Reader, *PrivateKey, crypto.Hash, []byte, *PSSOptions) ([]byte, error) {// Note that while we don't commit to deterministic execution with respect// to the rand stream, we also don't apply MaybeReadByte, so per Hyrum's Law// it's probably relied upon by some. It's a tolerable promise because a// well-specified number of random bytes is included in the signature, in a// well-specified way.if boring.Enabled && == boring.RandReader {, := boringPrivateKey()if != nil {return nil,}return boring.SignRSAPSS(, , , .saltLength())}boring.UnreachableExceptTests()if != nil && .Hash != 0 {= .Hash}:= .saltLength()switch {case PSSSaltLengthAuto:= (.N.BitLen()-1+7)/8 - 2 - .Size()if < 0 {return nil, ErrMessageTooLong}case PSSSaltLengthEqualsHash:= .Size()default:// If we get here saltLength is either > 0 or < -1, in the// latter case we fail out.if <= 0 {return nil, invalidSaltLenErr}}:= make([]byte, )if , := io.ReadFull(, ); != nil {return nil,}return signPSSWithSalt(, , , )}// VerifyPSS verifies a PSS signature.//// 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.//// The inputs are not considered confidential, and may leak through timing side// channels, or if an attacker has control of part of the inputs.func ( *PublicKey, crypto.Hash, []byte, []byte, *PSSOptions) error {if boring.Enabled {, := boringPublicKey()if != nil {return}if := boring.VerifyRSAPSS(, , , , .saltLength()); != nil {return ErrVerification}return nil}if len() != .Size() {return ErrVerification}// Salt length must be either one of the special constants (-1 or 0)// or otherwise positive. If it is < PSSSaltLengthEqualsHash (-1)// we return an error.if .saltLength() < PSSSaltLengthEqualsHash {return invalidSaltLenErr}:= .N.BitLen() - 1:= ( + 7) / 8, := encrypt(, )if != nil {return ErrVerification}// 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() > && len() > 0 {if [0] != 0 {return ErrVerification}= [1:]}return emsaPSSVerify(, , , .saltLength(), .New())}
![]() |
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |