| // 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) |
| } |