// 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.iflen() != {returnnil, errors.New("crypto/rsa: input must be hashed with given hash") }// 3. If emLen < hLen + sLen + 2, output "encoding error" and stop.if < ++2 {returnnil, 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. [] = 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() {returnerrors.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() {returnErrVerification }// 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.if < ++2 {returnErrVerification }// 4. If the rightmost octet of EM does not have hexadecimal value // 0xbc, output "inconsistent" and stop.if [-1] != 0xbc {returnErrVerification }// 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.varbyte = 0xff >> (8* - )if [0] & ^ != 0 {returnErrVerification }// 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 {returnErrVerification } = 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 {returnErrVerification } }if [] != 0x01 {returnErrVerification }// 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?returnErrVerification }returnnil}// 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 {returnnil, } := new(big.Int).SetBytes() , := decryptAndCheck(, , )if != nil {returnnil, } := 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.typePSSOptionsstruct {// 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 {returnPSSSaltLengthAuto }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 {casePSSSaltLengthAuto: = .Size() - 2 - .Size()casePSSSaltLengthEqualsHash: = .Size() } := make([]byte, )if , := io.ReadFull(, ); != nil {returnnil, }returnsignPSSWithSalt(, , , , )}// 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 {iflen() != .Size() {returnErrVerification } := new(big.Int).SetBytes() := encrypt(new(big.Int), , ) := .N.BitLen() - 1 := ( + 7) / 8if .BitLen() > *8 {returnErrVerification } := .FillBytes(make([]byte, ))returnemsaPSSVerify(, , , .saltLength(), .New())}
The pages are generated with Goldsv0.3.6. (GOOS=darwin 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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds.