/
signature.go
128 lines (118 loc) · 3.05 KB
/
signature.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright 2015 The Vanadium 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 security
import (
"crypto"
"crypto/sha256"
"crypto/sha512"
)
// Verify returns true iff sig is a valid signature for a message.
func (sig *Signature) Verify(key PublicKey, message []byte) bool {
if message = key.messageDigest(cryptoHash(sig.Hash), sig.Purpose, message); message == nil {
return false
}
return key.verify(message, sig)
}
// Digest returns a hash that is computed over all of the fields of the
// signature that are used for a particular signature algorithm. The
// digest can be used as a cache key or for 'chaining' as per
// Certificate.chainedDigests.
func (sig *Signature) digest(hashfn crypto.Hash) []byte {
var fields []byte
w := func(data []byte) {
fields = append(fields, cryptoSum(hashfn, data)...)
}
w([]byte(sig.Hash))
w(sig.Purpose)
switch {
case len(sig.R) > 0:
w([]byte("ECDSA")) // The signing algorithm
w(sig.R)
w(sig.S)
case len(sig.Ed25519) > 0:
w([]byte("ED25519")) // The signing algorithm
w(sig.Ed25519)
default:
w([]byte("RSA")) // The signing algorithm
w(sig.Rsa)
}
return cryptoSum(hashfn, fields)
}
// messageDigestFields returns a concatenation of the hashes of each field
// which consits of the key, the purpose and the message.
// In order to defend against "Duplicate Signature Key Selection (DSKS)" attacks
// as defined in the paper "Another look at Security Definition" by Neal Koblitz
// and Alfred Menzes, we also include the public key of the signer in the message
// being signed.
func messageDigestFields(hash crypto.Hash, publicKeyBytes, purpose, message []byte) []byte {
numFields := 3
fields := make([]byte, 0, hash.Size()*numFields)
w := func(data []byte) bool {
h := cryptoSum(hash, data)
if h == nil {
return false
}
fields = append(fields, h...)
return true
}
if !w(publicKeyBytes) {
return nil
}
if !w(message) {
return nil
}
if !w(purpose) {
return nil
}
return fields
}
func messageDigest(hash crypto.Hash, purpose, message []byte, key PublicKey) []byte {
keyBytes, err := key.MarshalBinary()
if err != nil {
return nil
}
return cryptoSum(hash, messageDigestFields(hash, keyBytes, purpose, message))
}
func cryptoSum(hash crypto.Hash, data []byte) []byte {
switch hash {
// case crypto.SHA1:
// h := sha1.Sum(data)
// return h[:]
case crypto.SHA256:
h := sha256.Sum256(data)
return h[:]
case crypto.SHA384:
h := sha512.Sum384(data)
return h[:]
case crypto.SHA512:
h := sha512.Sum512(data)
return h[:]
}
return nil
}
func cryptoHash(h Hash) crypto.Hash {
switch h {
// case SHA1Hash:
// return crypto.SHA1
case SHA256Hash:
return crypto.SHA256
case SHA384Hash:
return crypto.SHA384
case SHA512Hash:
return crypto.SHA512
}
return crypto.SHA512
}
type signerCommon struct {
pubkey PublicKey
chash crypto.Hash
vhash Hash
}
func newSignerCommon(pk PublicKey, hash Hash) signerCommon {
return signerCommon{
pubkey: pk,
vhash: hash,
chash: cryptoHash(hash),
}
}