Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1885)

Side by Side Diff: src/pkg/crypto/rsa/pss.go

Issue 9438043: code review 9438043: rsa: Implementation of RSASSA-PSS signature algorithm a...
Patch Set: diff -r 1abed5873071 https://code.google.com/p/go Created 10 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pkg/crypto/rsa/emsa_test.go ('k') | src/pkg/crypto/rsa/pssvect_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 package rsa
2
3 // This file implemented the RSASSA-PSS signature algorithms [1].
4 //
5 // 1. http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptograph y-standard.pdf
6 import (
7 "bytes"
8 "crypto"
9 "errors"
10 "hash"
11 "io"
12 "math/big"
13 )
14
15 func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt e, error) {
16 // See [1], section 9.1.1
17 hLen := hash.Size()
18 sLen := len(salt)
19 emLen := (emBits + 7) / 8
20
21 // 1. If the length of M is greater than the input limitation for the
22 // hash function (2^61 - 1 octets for SHA-1), output "message too
23 // long" and stop.
24 //
25 // 2. Let mHash = Hash(M), an octet string of length hLen.
26
27 if len(mHash) != hLen {
28 return nil, errors.New("crypto/rsa: input must be hashed message ")
29 }
30
31 // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop.
32
33 if emLen < hLen+sLen+2 {
34 return nil, errors.New("crypto/rsa: encoding error")
35 }
36
37 em := make([]byte, emLen)
38 db := em[:emLen-sLen-hLen-2+1+sLen]
39 h := em[emLen-sLen-hLen-2+1+sLen : emLen-1]
40
41 // 4. Generate a random octet string salt of length sLen; if sLen = 0,
42 // then salt is the empty string.
43 //
44 // 5. Let
45 // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt;
46 //
47 // M' is an octet string of length 8 + hLen + sLen with eight
48 // initial zero octets.
49 //
50 // 6. Let H = Hash(M'), an octet string of length hLen.
51
52 var prefix [8]byte
53
54 hash.Write(prefix[:])
55 hash.Write(mHash)
56 hash.Write(salt)
57
58 h = hash.Sum(h[:0])
59 hash.Reset()
60
61 // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
62 // zero octets. The length of PS may be 0.
63 //
64 // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
65 // emLen - hLen - 1.
66
67 db[emLen-sLen-hLen-2] = 0x01
68 copy(db[emLen-sLen-hLen-1:], salt)
69
70 // 9. Let dbMask = MGF(H, emLen - hLen - 1).
71 //
72 // 10. Let maskedDB = DB \xor dbMask.
73
74 mgf1XOR(db, hash, h)
75
76 // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in
77 // maskedDB to zero.
78
79 db[0] &= (0xFF >> uint(8*emLen-emBits))
80
81 // 12. Let EM = maskedDB || H || 0xbc.
82 em[emLen-1] = 0xBC
83
84 // 13. Output EM.
85 return em, nil
86 }
87
88 func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error {
89 // 1. If the length of M is greater than the input limitation for the
90 // hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
91 // and stop.
92 //
93 // 2. Let mHash = Hash(M), an octet string of length hLen.
94 hLen := hash.Size()
95 if hLen != len(mHash) {
96 return ErrVerification
97 }
98
99 // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.
100 emLen := (emBits + 7) / 8
101 if emLen < hLen+sLen+2 {
102 return ErrVerification
103 }
104
105 // 4. If the rightmost octet of EM does not have hexadecimal value
106 // 0xbc, output "inconsistent" and stop.
107 if em[len(em)-1] != 0xBC {
108 return ErrVerification
109 }
110
111 // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
112 // let H be the next hLen octets.
113 db := em[:emLen-hLen-1]
114 h := em[emLen-hLen-1 : len(em)-1]
115
116 // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in
117 // maskedDB are not all equal to zero, output "inconsistent" and
118 // stop.
119 if em[0]&(0xFF<<uint(8-(8*emLen-emBits))) != 0 {
120 return ErrVerification
121 }
122
123 // 7. Let dbMask = MGF(H, emLen - hLen - 1).
124 //
125 // 8. Let DB = maskedDB \xor dbMask.
126 mgf1XOR(db, hash, h)
127
128 // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
129 // to zero.
130 db[0] &= (0xFF >> uint(8*emLen-emBits))
131
132 // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
133 // or if the octet at position emLen - hLen - sLen - 1 (the leftmost
134 // position is "position 1") does not have hexadecimal value 0x01,
135 // output "inconsistent" and stop.
136 for _, e := range db[:emLen-hLen-sLen-2] {
137 if e != 0x00 {
138 return ErrVerification
139 }
140 }
141 if db[emLen-hLen-sLen-2] != 0x01 {
142 return ErrVerification
143 }
144
145 // 11. Let salt be the last sLen octets of DB.
146 salt := db[len(db)-sLen:]
147
148 // 12. Let
149 // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
150 // M' is an octet string of length 8 + hLen + sLen with eight
151 // initial zero octets.
152 //
153 // 13. Let H' = Hash(M'), an octet string of length hLen.
154 var prefix [8]byte
155 hash.Write(prefix[:])
156 hash.Write(mHash)
157 hash.Write(salt)
158
159 h0 := hash.Sum(nil)
160
161 // 14. If H = H', output "consistent." Otherwise, output "inconsistent."
162 if !bytes.Equal(h0, h) {
163 return ErrVerification
164 }
165 return nil
166 }
167
168 // signPSSWithSalt calculates the signature of hashed using RSASSA-PSS [1] with specified salt.
169 // Note that hashed must be the result of hashing the input message using the gi ven hash funcion.
170 // salt is a random sequence of bytes whose length will be later used to verify the signature.
171 func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, salt []byte) (s []byte, err error) {
172 nBits := priv.N.BitLen()
173 em, err := emsaPSSEncode(hashed, nBits-1, salt, hash.New())
174 if err != nil {
175 return
176 }
177 m := new(big.Int).SetBytes(em)
178 c, err := decrypt(rand, priv, m)
179 if err != nil {
180 return
181 }
182 s = make([]byte, (nBits+7)/8)
183 copyWithLeftPad(s, c.Bytes())
184 return
185 }
186
187 // SignPSS calculates the signature of hashed using RSASSA-PSS [1].
188 // Note that hashed must be the result of hashing the input message using the gi ven hash funcion.
189 // saltLen is size of the salt. Usually it is the same size as the digest genera ted by the hash.
190 func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, saltLen int) (s []byte, err error) {
agl1 2013/05/20 19:56:23 Some reorganisation is probably needed before land
Nan Deng 2013/05/20 20:19:58 I agree. After a reading of more details, I would
191 salt := make([]byte, saltLen)
192 _, err = io.ReadFull(rand, salt)
193 if err != nil {
194 return
195 }
196 s, err = signPSSWithSalt(rand, priv, hash, hashed, salt)
197 return
198 }
199
200 // VerifyPSS verifies an RSASSA-PSS signature.
201 // hashed is the result of hashing the input message using the given hash functi on and sig is the signature.
202 // A valid signature is indicated by returning a nil error.
203 // saltLen is number of bytes of the salt used to sign the message.
204 func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, salt Len int) error {
205 nBits := pub.N.BitLen()
206 if len(sig) != (nBits+7)/8 {
207 return ErrVerification
208 }
209 s := new(big.Int).SetBytes(sig)
210 m := encrypt(new(big.Int), pub, s)
211 emBits := nBits - 1
212 emLen := (emBits + 7) / 8
213 if emLen < len(m.Bytes()) {
214 return ErrVerification
215 }
216 em := make([]byte, emLen)
217 copyWithLeftPad(em, m.Bytes())
218 if err := emsaPSSVerify(hashed, em, emBits, saltLen, hash.New()); err != nil {
219 return err
220 }
221 return nil
222 }
OLDNEW
« no previous file with comments | « src/pkg/crypto/rsa/emsa_test.go ('k') | src/pkg/crypto/rsa/pssvect_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b