1
// Copyright 2011 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.
8
"code.google.com/p/go.crypto/openpgp/elgamal"
9
"code.google.com/p/go.crypto/openpgp/errors"
22
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
23
type PublicKey struct {
24
CreationTime time.Time
25
PubKeyAlgo PublicKeyAlgorithm
26
PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
31
n, e, p, q, g, y parsedMPI
34
func fromBig(n *big.Int) parsedMPI {
37
bitLength: uint16(n.BitLen()),
41
// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
42
func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey {
44
CreationTime: creationTime,
45
PubKeyAlgo: PubKeyAlgoRSA,
48
e: fromBig(big.NewInt(int64(pub.E))),
51
pk.setFingerPrintAndKeyId()
55
// NewDSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
56
func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey {
58
CreationTime: creationTime,
59
PubKeyAlgo: PubKeyAlgoDSA,
67
pk.setFingerPrintAndKeyId()
71
func (pk *PublicKey) parse(r io.Reader) (err error) {
72
// RFC 4880, section 5.5.2
74
_, err = readFull(r, buf[:])
79
return errors.UnsupportedError("public key version")
81
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
82
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
83
switch pk.PubKeyAlgo {
84
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
88
case PubKeyAlgoElGamal:
89
err = pk.parseElGamal(r)
91
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
97
pk.setFingerPrintAndKeyId()
101
func (pk *PublicKey) setFingerPrintAndKeyId() {
102
// RFC 4880, section 12.2
103
fingerPrint := sha1.New()
104
pk.SerializeSignaturePrefix(fingerPrint)
105
pk.serializeWithoutHeaders(fingerPrint)
106
copy(pk.Fingerprint[:], fingerPrint.Sum(nil))
107
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
110
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
112
func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
113
pk.n.bytes, pk.n.bitLength, err = readMPI(r)
117
pk.e.bytes, pk.e.bitLength, err = readMPI(r)
122
if len(pk.e.bytes) > 3 {
123
err = errors.UnsupportedError("large public exponent")
126
rsa := &rsa.PublicKey{
127
N: new(big.Int).SetBytes(pk.n.bytes),
130
for i := 0; i < len(pk.e.bytes); i++ {
132
rsa.E |= int(pk.e.bytes[i])
138
// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
140
func (pk *PublicKey) parseDSA(r io.Reader) (err error) {
141
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
145
pk.q.bytes, pk.q.bitLength, err = readMPI(r)
149
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
153
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
158
dsa := new(dsa.PublicKey)
159
dsa.P = new(big.Int).SetBytes(pk.p.bytes)
160
dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
161
dsa.G = new(big.Int).SetBytes(pk.g.bytes)
162
dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
167
// parseElGamal parses ElGamal public key material from the given Reader. See
168
// RFC 4880, section 5.5.2.
169
func (pk *PublicKey) parseElGamal(r io.Reader) (err error) {
170
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
174
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
178
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
183
elgamal := new(elgamal.PublicKey)
184
elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
185
elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
186
elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
187
pk.PublicKey = elgamal
191
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
192
// The prefix is used when calculating a signature over this public key. See
193
// RFC 4880, section 5.2.4.
194
func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
196
switch pk.PubKeyAlgo {
197
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
198
pLength += 2 + uint16(len(pk.n.bytes))
199
pLength += 2 + uint16(len(pk.e.bytes))
201
pLength += 2 + uint16(len(pk.p.bytes))
202
pLength += 2 + uint16(len(pk.q.bytes))
203
pLength += 2 + uint16(len(pk.g.bytes))
204
pLength += 2 + uint16(len(pk.y.bytes))
205
case PubKeyAlgoElGamal:
206
pLength += 2 + uint16(len(pk.p.bytes))
207
pLength += 2 + uint16(len(pk.g.bytes))
208
pLength += 2 + uint16(len(pk.y.bytes))
210
panic("unknown public key algorithm")
213
h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
217
func (pk *PublicKey) Serialize(w io.Writer) (err error) {
218
length := 6 // 6 byte header
220
switch pk.PubKeyAlgo {
221
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
222
length += 2 + len(pk.n.bytes)
223
length += 2 + len(pk.e.bytes)
225
length += 2 + len(pk.p.bytes)
226
length += 2 + len(pk.q.bytes)
227
length += 2 + len(pk.g.bytes)
228
length += 2 + len(pk.y.bytes)
229
case PubKeyAlgoElGamal:
230
length += 2 + len(pk.p.bytes)
231
length += 2 + len(pk.g.bytes)
232
length += 2 + len(pk.y.bytes)
234
panic("unknown public key algorithm")
237
packetType := packetTypePublicKey
239
packetType = packetTypePublicSubkey
241
err = serializeHeader(w, packetType, length)
245
return pk.serializeWithoutHeaders(w)
248
// serializeWithoutHeaders marshals the PublicKey to w in the form of an
249
// OpenPGP public key packet, not including the packet header.
250
func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
253
t := uint32(pk.CreationTime.Unix())
254
buf[1] = byte(t >> 24)
255
buf[2] = byte(t >> 16)
256
buf[3] = byte(t >> 8)
258
buf[5] = byte(pk.PubKeyAlgo)
260
_, err = w.Write(buf[:])
265
switch pk.PubKeyAlgo {
266
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
267
return writeMPIs(w, pk.n, pk.e)
269
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
270
case PubKeyAlgoElGamal:
271
return writeMPIs(w, pk.p, pk.g, pk.y)
273
return errors.InvalidArgumentError("bad public-key algorithm")
276
// CanSign returns true iff this public key can generate signatures
277
func (pk *PublicKey) CanSign() bool {
278
return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
281
// VerifySignature returns nil iff sig is a valid signature, made by this
282
// public key, of the data hashed into signed. signed is mutated by this call.
283
func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
285
return errors.InvalidArgumentError("public key cannot generate signatures")
288
signed.Write(sig.HashSuffix)
289
hashBytes := signed.Sum(nil)
291
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
292
return errors.SignatureError("hash tag doesn't match")
295
if pk.PubKeyAlgo != sig.PubKeyAlgo {
296
return errors.InvalidArgumentError("public key and signature use different algorithms")
299
switch pk.PubKeyAlgo {
300
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
301
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
302
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
304
return errors.SignatureError("RSA verification failure")
308
dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
309
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
310
subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
311
if len(hashBytes) > subgroupSize {
312
hashBytes = hashBytes[:subgroupSize]
314
if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
315
return errors.SignatureError("DSA verification failure")
319
panic("shouldn't happen")
324
// keySignatureHash returns a Hash of the message that needs to be signed for
325
// pk to assert a subkey relationship to signed.
326
func keySignatureHash(pk, signed *PublicKey, sig *Signature) (h hash.Hash, err error) {
329
return nil, errors.UnsupportedError("hash function")
332
// RFC 4880, section 5.2.4
333
pk.SerializeSignaturePrefix(h)
334
pk.serializeWithoutHeaders(h)
335
signed.SerializeSignaturePrefix(h)
336
signed.serializeWithoutHeaders(h)
340
// VerifyKeySignature returns nil iff sig is a valid signature, made by this
341
// public key, of signed.
342
func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err error) {
343
h, err := keySignatureHash(pk, signed, sig)
347
return pk.VerifySignature(h, sig)
350
// userIdSignatureHash returns a Hash of the message that needs to be signed
351
// to assert that pk is a valid key for id.
352
func userIdSignatureHash(id string, pk *PublicKey, sig *Signature) (h hash.Hash, err error) {
355
return nil, errors.UnsupportedError("hash function")
358
// RFC 4880, section 5.2.4
359
pk.SerializeSignaturePrefix(h)
360
pk.serializeWithoutHeaders(h)
364
buf[1] = byte(len(id) >> 24)
365
buf[2] = byte(len(id) >> 16)
366
buf[3] = byte(len(id) >> 8)
367
buf[4] = byte(len(id))
374
// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
375
// public key, of id.
376
func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err error) {
377
h, err := userIdSignatureHash(id, pk, sig)
381
return pk.VerifySignature(h, sig)
384
// KeyIdString returns the public key's fingerprint in capital hex
385
// (e.g. "6C7EE1B8621CC013").
386
func (pk *PublicKey) KeyIdString() string {
387
return fmt.Sprintf("%X", pk.Fingerprint[12:20])
390
// KeyIdShortString returns the short form of public key's fingerprint
391
// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
392
func (pk *PublicKey) KeyIdShortString() string {
393
return fmt.Sprintf("%X", pk.Fingerprint[16:20])
396
// A parsedMPI is used to store the contents of a big integer, along with the
397
// bit length that was specified in the original input. This allows the MPI to
398
// be reserialized exactly.
399
type parsedMPI struct {
404
// writeMPIs is a utility function for serializing several big integers to the
406
func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) {
407
for _, mpi := range mpis {
408
err = writeMPI(w, mpi.bitLength, mpi.bytes)
416
// BitLength returns the bit length for the given public key.
417
func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
418
switch pk.PubKeyAlgo {
419
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
420
bitLength = pk.n.bitLength
422
bitLength = pk.p.bitLength
423
case PubKeyAlgoElGamal:
424
bitLength = pk.p.bitLength
426
err = errors.InvalidArgumentError("bad public-key algorithm")