| // 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/openpgp/armor" |
| "crypto/openpgp/error" |
| "crypto/openpgp/packet" |
| "crypto/rand" |
| _ "crypto/sha256" |
| "io" |
| "os" |
| "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) |
| |
| err = sig.Sign(h, signer.PrivateKey) |
| if err != nil { |
| return |
| } |
| |
| return sig.Serialize(w) |
| } |
| |
| // FileHints contains metadata about encrypted files. This metadata is, itself, |
| // encrypted. |
| type FileHints struct { |
| // IsBinary can be set to hint that the contents are binary data. |
| IsBinary bool |
| // FileName hints at the name of the file that should be written. It's |
| // truncated to 255 bytes if longer. It may be empty to suggest that the |
| // file should not be written to disk. It may be equal to "_CONSOLE" to |
| // suggest the data should not be written to disk. |
| FileName string |
| // EpochSeconds contains the modification time of the file, or 0 if not applicable. |
| EpochSeconds uint32 |
| } |
| |
| // SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase. |
| // The resulting WriteCloser MUST be closed after the contents of the file have |
| // been written. |
| func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints) (plaintext io.WriteCloser, err os.Error) { |
| if hints == nil { |
| hints = &FileHints{} |
| } |
| |
| key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, rand.Reader, passphrase, packet.CipherAES128) |
| if err != nil { |
| return |
| } |
| w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, packet.CipherAES128, key) |
| if err != nil { |
| return |
| } |
| return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) |
| } |