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, errors.New("crypto/rsa: key size too small for PSS signature")
}
:= 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.
[] = 0x01
copy([+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) / 8
if != 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.
:= - - - 2
for , := 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 ( io.Reader, *PrivateKey, crypto.Hash, , []byte) ([]byte, error) {
:= .N.BitLen() - 1
, := emsaPSSEncode(, , , .New())
if != nil {
return nil,
}
:= new(big.Int).SetBytes()
, := decryptAndCheck(, , )
if != nil {
return nil,
}
:= make([]byte, .Size())
return .FillBytes(), nil
}
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 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
}
// 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.
func ( io.Reader, *PrivateKey, crypto.Hash, []byte, *PSSOptions) ([]byte, error) {
if != nil && .Hash != 0 {
= .Hash
}
:= .saltLength()
switch {
case PSSSaltLengthAuto:
= (.N.BitLen()-1+7)/8 - 2 - .Size()
case PSSSaltLengthEqualsHash:
= .Size()
}
:= 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.
func ( *PublicKey, crypto.Hash, []byte, []byte, *PSSOptions) error {
if len() != .Size() {
return ErrVerification
}
:= new(big.Int).SetBytes()
:= encrypt(new(big.Int), , )
:= .N.BitLen() - 1
:= ( + 7) / 8
if .BitLen() > *8 {
return ErrVerification
}
:= .FillBytes(make([]byte, ))
return emsaPSSVerify(, , , .saltLength(), .New())
}
The pages are generated with Golds v0.4.9. (GOOS=linux GOARCH=amd64)