github.com/insolar/x-crypto@v0.0.0-20191031140942-75fab8a325f6/rsa/pss_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rsa 6 7 import ( 8 "bufio" 9 "bytes" 10 "compress/bzip2" 11 "encoding/hex" 12 "github.com/insolar/x-crypto" 13 _ "github.com/insolar/x-crypto/md5" 14 "github.com/insolar/x-crypto/rand" 15 "github.com/insolar/x-crypto/sha1" 16 _ "github.com/insolar/x-crypto/sha256" 17 "math/big" 18 "os" 19 "strconv" 20 "strings" 21 "testing" 22 ) 23 24 func TestEMSAPSS(t *testing.T) { 25 // Test vector in file pss-int.txt from: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip 26 msg := []byte{ 27 0x85, 0x9e, 0xef, 0x2f, 0xd7, 0x8a, 0xca, 0x00, 0x30, 0x8b, 28 0xdc, 0x47, 0x11, 0x93, 0xbf, 0x55, 0xbf, 0x9d, 0x78, 0xdb, 29 0x8f, 0x8a, 0x67, 0x2b, 0x48, 0x46, 0x34, 0xf3, 0xc9, 0xc2, 30 0x6e, 0x64, 0x78, 0xae, 0x10, 0x26, 0x0f, 0xe0, 0xdd, 0x8c, 31 0x08, 0x2e, 0x53, 0xa5, 0x29, 0x3a, 0xf2, 0x17, 0x3c, 0xd5, 32 0x0c, 0x6d, 0x5d, 0x35, 0x4f, 0xeb, 0xf7, 0x8b, 0x26, 0x02, 33 0x1c, 0x25, 0xc0, 0x27, 0x12, 0xe7, 0x8c, 0xd4, 0x69, 0x4c, 34 0x9f, 0x46, 0x97, 0x77, 0xe4, 0x51, 0xe7, 0xf8, 0xe9, 0xe0, 35 0x4c, 0xd3, 0x73, 0x9c, 0x6b, 0xbf, 0xed, 0xae, 0x48, 0x7f, 36 0xb5, 0x56, 0x44, 0xe9, 0xca, 0x74, 0xff, 0x77, 0xa5, 0x3c, 37 0xb7, 0x29, 0x80, 0x2f, 0x6e, 0xd4, 0xa5, 0xff, 0xa8, 0xba, 38 0x15, 0x98, 0x90, 0xfc, 39 } 40 salt := []byte{ 41 0xe3, 0xb5, 0xd5, 0xd0, 0x02, 0xc1, 0xbc, 0xe5, 0x0c, 0x2b, 42 0x65, 0xef, 0x88, 0xa1, 0x88, 0xd8, 0x3b, 0xce, 0x7e, 0x61, 43 } 44 expected := []byte{ 45 0x66, 0xe4, 0x67, 0x2e, 0x83, 0x6a, 0xd1, 0x21, 0xba, 0x24, 46 0x4b, 0xed, 0x65, 0x76, 0xb8, 0x67, 0xd9, 0xa4, 0x47, 0xc2, 47 0x8a, 0x6e, 0x66, 0xa5, 0xb8, 0x7d, 0xee, 0x7f, 0xbc, 0x7e, 48 0x65, 0xaf, 0x50, 0x57, 0xf8, 0x6f, 0xae, 0x89, 0x84, 0xd9, 49 0xba, 0x7f, 0x96, 0x9a, 0xd6, 0xfe, 0x02, 0xa4, 0xd7, 0x5f, 50 0x74, 0x45, 0xfe, 0xfd, 0xd8, 0x5b, 0x6d, 0x3a, 0x47, 0x7c, 51 0x28, 0xd2, 0x4b, 0xa1, 0xe3, 0x75, 0x6f, 0x79, 0x2d, 0xd1, 52 0xdc, 0xe8, 0xca, 0x94, 0x44, 0x0e, 0xcb, 0x52, 0x79, 0xec, 53 0xd3, 0x18, 0x3a, 0x31, 0x1f, 0xc8, 0x96, 0xda, 0x1c, 0xb3, 54 0x93, 0x11, 0xaf, 0x37, 0xea, 0x4a, 0x75, 0xe2, 0x4b, 0xdb, 55 0xfd, 0x5c, 0x1d, 0xa0, 0xde, 0x7c, 0xec, 0xdf, 0x1a, 0x89, 56 0x6f, 0x9d, 0x8b, 0xc8, 0x16, 0xd9, 0x7c, 0xd7, 0xa2, 0xc4, 57 0x3b, 0xad, 0x54, 0x6f, 0xbe, 0x8c, 0xfe, 0xbc, 58 } 59 60 hash := sha1.New() 61 hash.Write(msg) 62 hashed := hash.Sum(nil) 63 64 encoded, err := emsaPSSEncode(hashed, 1023, salt, sha1.New()) 65 if err != nil { 66 t.Errorf("Error from emsaPSSEncode: %s\n", err) 67 } 68 if !bytes.Equal(encoded, expected) { 69 t.Errorf("Bad encoding. got %x, want %x", encoded, expected) 70 } 71 72 if err = emsaPSSVerify(hashed, encoded, 1023, len(salt), sha1.New()); err != nil { 73 t.Errorf("Bad verification: %s", err) 74 } 75 } 76 77 // TestPSSGolden tests all the test vectors in pss-vect.txt from 78 // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip 79 func TestPSSGolden(t *testing.T) { 80 inFile, err := os.Open("testdata/pss-vect.txt.bz2") 81 if err != nil { 82 t.Fatalf("Failed to open input file: %s", err) 83 } 84 defer inFile.Close() 85 86 // The pss-vect.txt file contains RSA keys and then a series of 87 // signatures. A goroutine is used to preprocess the input by merging 88 // lines, removing spaces in hex values and identifying the start of 89 // new keys and signature blocks. 90 const newKeyMarker = "START NEW KEY" 91 const newSignatureMarker = "START NEW SIGNATURE" 92 93 values := make(chan string) 94 95 go func() { 96 defer close(values) 97 scanner := bufio.NewScanner(bzip2.NewReader(inFile)) 98 var partialValue string 99 lastWasValue := true 100 101 for scanner.Scan() { 102 line := scanner.Text() 103 switch { 104 case len(line) == 0: 105 if len(partialValue) > 0 { 106 values <- strings.Replace(partialValue, " ", "", -1) 107 partialValue = "" 108 lastWasValue = true 109 } 110 continue 111 case strings.HasPrefix(line, "# ======") && lastWasValue: 112 values <- newKeyMarker 113 lastWasValue = false 114 case strings.HasPrefix(line, "# ------") && lastWasValue: 115 values <- newSignatureMarker 116 lastWasValue = false 117 case strings.HasPrefix(line, "#"): 118 continue 119 default: 120 partialValue += line 121 } 122 } 123 if err := scanner.Err(); err != nil { 124 panic(err) 125 } 126 }() 127 128 var key *PublicKey 129 var hashed []byte 130 hash := crypto.SHA1 131 h := hash.New() 132 opts := &PSSOptions{ 133 SaltLength: PSSSaltLengthEqualsHash, 134 } 135 136 for marker := range values { 137 switch marker { 138 case newKeyMarker: 139 key = new(PublicKey) 140 nHex, ok := <-values 141 if !ok { 142 continue 143 } 144 key.N = bigFromHex(nHex) 145 key.E = intFromHex(<-values) 146 // We don't care for d, p, q, dP, dQ or qInv. 147 for i := 0; i < 6; i++ { 148 <-values 149 } 150 case newSignatureMarker: 151 msg := fromHex(<-values) 152 <-values // skip salt 153 sig := fromHex(<-values) 154 155 h.Reset() 156 h.Write(msg) 157 hashed = h.Sum(hashed[:0]) 158 159 if err := VerifyPSS(key, hash, hashed, sig, opts); err != nil { 160 t.Error(err) 161 } 162 default: 163 t.Fatalf("unknown marker: " + marker) 164 } 165 } 166 } 167 168 // TestPSSOpenSSL ensures that we can verify a PSS signature from OpenSSL with 169 // the default options. OpenSSL sets the salt length to be maximal. 170 func TestPSSOpenSSL(t *testing.T) { 171 hash := crypto.SHA256 172 h := hash.New() 173 h.Write([]byte("testing")) 174 hashed := h.Sum(nil) 175 176 // Generated with `echo -n testing | openssl dgst -sign key.pem -sigopt rsa_padding_mode:pss -sha256 > sig` 177 sig := []byte{ 178 0x95, 0x59, 0x6f, 0xd3, 0x10, 0xa2, 0xe7, 0xa2, 0x92, 0x9d, 179 0x4a, 0x07, 0x2e, 0x2b, 0x27, 0xcc, 0x06, 0xc2, 0x87, 0x2c, 180 0x52, 0xf0, 0x4a, 0xcc, 0x05, 0x94, 0xf2, 0xc3, 0x2e, 0x20, 181 0xd7, 0x3e, 0x66, 0x62, 0xb5, 0x95, 0x2b, 0xa3, 0x93, 0x9a, 182 0x66, 0x64, 0x25, 0xe0, 0x74, 0x66, 0x8c, 0x3e, 0x92, 0xeb, 183 0xc6, 0xe6, 0xc0, 0x44, 0xf3, 0xb4, 0xb4, 0x2e, 0x8c, 0x66, 184 0x0a, 0x37, 0x9c, 0x69, 185 } 186 187 if err := VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, nil); err != nil { 188 t.Error(err) 189 } 190 } 191 192 func TestPSSNilOpts(t *testing.T) { 193 hash := crypto.SHA256 194 h := hash.New() 195 h.Write([]byte("testing")) 196 hashed := h.Sum(nil) 197 198 SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil) 199 } 200 201 func TestPSSSigning(t *testing.T) { 202 var saltLengthCombinations = []struct { 203 signSaltLength, verifySaltLength int 204 good bool 205 }{ 206 {PSSSaltLengthAuto, PSSSaltLengthAuto, true}, 207 {PSSSaltLengthEqualsHash, PSSSaltLengthAuto, true}, 208 {PSSSaltLengthEqualsHash, PSSSaltLengthEqualsHash, true}, 209 {PSSSaltLengthEqualsHash, 8, false}, 210 {PSSSaltLengthAuto, PSSSaltLengthEqualsHash, false}, 211 {8, 8, true}, 212 } 213 214 hash := crypto.MD5 215 h := hash.New() 216 h.Write([]byte("testing")) 217 hashed := h.Sum(nil) 218 var opts PSSOptions 219 220 for i, test := range saltLengthCombinations { 221 opts.SaltLength = test.signSaltLength 222 sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts) 223 if err != nil { 224 t.Errorf("#%d: error while signing: %s", i, err) 225 continue 226 } 227 228 opts.SaltLength = test.verifySaltLength 229 err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts) 230 if (err == nil) != test.good { 231 t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err) 232 } 233 } 234 } 235 236 func bigFromHex(hex string) *big.Int { 237 n, ok := new(big.Int).SetString(hex, 16) 238 if !ok { 239 panic("bad hex: " + hex) 240 } 241 return n 242 } 243 244 func intFromHex(hex string) int { 245 i, err := strconv.ParseInt(hex, 16, 32) 246 if err != nil { 247 panic(err) 248 } 249 return int(i) 250 } 251 252 func fromHex(hexStr string) []byte { 253 s, err := hex.DecodeString(hexStr) 254 if err != nil { 255 panic(err) 256 } 257 return s 258 }