summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/openpgp/write.go
blob: ef7b11230a987ac55f230504d6da617e7bcaa748 (plain)
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
// Copyright 2011 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 openpgp

import (
	"crypto"
	"crypto/dsa"
	"crypto/openpgp/armor"
	"crypto/openpgp/error"
	"crypto/openpgp/packet"
	"crypto/rsa"
	_ "crypto/sha256"
	"io"
	"os"
	"strconv"
	"time"
)

// DetachSign signs message with the private key from signer (which must
// already have been decrypted) and writes the signature to w.
func DetachSign(w io.Writer, signer *Entity, message io.Reader) os.Error {
	return detachSign(w, signer, message, packet.SigTypeBinary)
}

// ArmoredDetachSign signs message with the private key from signer (which
// must already have been decrypted) and writes an armored signature to w.
func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader) (err os.Error) {
	return armoredDetachSign(w, signer, message, packet.SigTypeBinary)
}

// DetachSignText signs message (after canonicalising the line endings) with
// the private key from signer (which must already have been decrypted) and
// writes the signature to w.
func DetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
	return detachSign(w, signer, message, packet.SigTypeText)
}

// ArmoredDetachSignText signs message (after canonicalising the line endings)
// with the private key from signer (which must already have been decrypted)
// and writes an armored signature to w.
func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
	return armoredDetachSign(w, signer, message, packet.SigTypeText)
}

func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err os.Error) {
	out, err := armor.Encode(w, SignatureType, nil)
	if err != nil {
		return
	}
	err = detachSign(out, signer, message, sigType)
	if err != nil {
		return
	}
	return out.Close()
}

func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err os.Error) {
	if signer.PrivateKey == nil {
		return error.InvalidArgumentError("signing key doesn't have a private key")
	}
	if signer.PrivateKey.Encrypted {
		return error.InvalidArgumentError("signing key is encrypted")
	}

	sig := new(packet.Signature)
	sig.SigType = sigType
	sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
	sig.Hash = crypto.SHA256
	sig.CreationTime = uint32(time.Seconds())
	sig.IssuerKeyId = &signer.PrivateKey.KeyId

	h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
	if err != nil {
		return
	}
	io.Copy(wrappedHash, message)

	switch signer.PrivateKey.PubKeyAlgo {
	case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSASignOnly:
		priv := signer.PrivateKey.PrivateKey.(*rsa.PrivateKey)
		err = sig.SignRSA(h, priv)
	case packet.PubKeyAlgoDSA:
		priv := signer.PrivateKey.PrivateKey.(*dsa.PrivateKey)
		err = sig.SignDSA(h, priv)
	default:
		err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
	}

	if err != nil {
		return
	}

	return sig.Serialize(w)
}