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 (
	
	
	
	
	

	
	
	
	
)
DetachSign signs message with the private key from signer (which must already have been decrypted) and writes the signature to w. If config is nil, sensible defaults will be used.
func ( io.Writer,  *Entity,  io.Reader,  *packet.Config) error {
	return detachSign(, , , packet.SigTypeBinary, )
}
ArmoredDetachSign signs message with the private key from signer (which must already have been decrypted) and writes an armored signature to w. If config is nil, sensible defaults will be used.
func ( io.Writer,  *Entity,  io.Reader,  *packet.Config) ( error) {
	return armoredDetachSign(, , , 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. If config is nil, sensible defaults will be used.
func ( io.Writer,  *Entity,  io.Reader,  *packet.Config) error {
	return detachSign(, , , 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. If config is nil, sensible defaults will be used.
func ( io.Writer,  *Entity,  io.Reader,  *packet.Config) error {
	return armoredDetachSign(, , , packet.SigTypeText, )
}

func ( io.Writer,  *Entity,  io.Reader,  packet.SignatureType,  *packet.Config) ( error) {
	,  := armor.Encode(, SignatureType, nil)
	if  != nil {
		return
	}
	 = detachSign(, , , , )
	if  != nil {
		return
	}
	return .Close()
}

func ( io.Writer,  *Entity,  io.Reader,  packet.SignatureType,  *packet.Config) ( error) {
	if .PrivateKey == nil {
		return errors.InvalidArgumentError("signing key doesn't have a private key")
	}
	if .PrivateKey.Encrypted {
		return errors.InvalidArgumentError("signing key is encrypted")
	}

	 := new(packet.Signature)
	.SigType = 
	.PubKeyAlgo = .PrivateKey.PubKeyAlgo
	.Hash = .Hash()
	.CreationTime = .Now()
	.IssuerKeyId = &.PrivateKey.KeyId

	, ,  := hashForSignature(.Hash, .SigType)
	if  != nil {
		return
	}
	io.Copy(, )

	 = .Sign(, .PrivateKey, )
	if  != nil {
		return
	}

	return .Serialize()
}
FileHints contains metadata about encrypted files. This metadata is, itself, encrypted.
IsBinary can be set to hint that the contents are binary data.
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.
ModTime contains the modification time of the file, or the zero time if not applicable.
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. If config is nil, sensible defaults will be used.
func ( io.Writer,  []byte,  *FileHints,  *packet.Config) ( io.WriteCloser,  error) {
	if  == nil {
		 = &FileHints{}
	}

	,  := packet.SerializeSymmetricKeyEncrypted(, , )
	if  != nil {
		return
	}
	,  := packet.SerializeSymmetricallyEncrypted(, .Cipher(), , )
	if  != nil {
		return
	}

	 := 
	if  := .Compression();  != packet.CompressionNone {
		var  *packet.CompressionConfig
		if  != nil {
			 = .CompressionConfig
		}
		,  = packet.SerializeCompressed(, , )
		if  != nil {
			return
		}
	}

	var  uint32
	if !.ModTime.IsZero() {
		 = uint32(.ModTime.Unix())
	}
	return packet.SerializeLiteral(, .IsBinary, .FileName, )
}
intersectPreferences mutates and returns a prefix of a that contains only the values in the intersection of a and b. The order of a is preserved.
func ( []uint8,  []uint8) ( []uint8) {
	var  int
	for ,  := range  {
		for ,  := range  {
			if  ==  {
				[] = 
				++
				break
			}
		}
	}

	return [:]
}

func ( crypto.Hash) uint8 {
	,  := s2k.HashToHashId()
	if ! {
		panic("tried to convert unknown hash")
	}
	return 
}
writeAndSign writes the data as a payload package and, optionally, signs it. hints contains optional information, that is also encrypted, that aids the recipients in processing the message. The resulting WriteCloser must be closed after the contents of the file have been written. If config is nil, sensible defaults will be used.
func ( io.WriteCloser,  []uint8,  *Entity,  *FileHints,  *packet.Config) ( io.WriteCloser,  error) {
	var  *packet.PrivateKey
	if  != nil {
		,  := .signingKey(.Now())
		if ! {
			return nil, errors.InvalidArgumentError("no valid signing keys")
		}
		 = .PrivateKey
		if  == nil {
			return nil, errors.InvalidArgumentError("no private key in signing key")
		}
		if .Encrypted {
			return nil, errors.InvalidArgumentError("signing key must be decrypted")
		}
	}

	var  crypto.Hash
	for ,  := range  {
		if ,  := s2k.HashIdToHash();  && .Available() {
			 = 
			break
		}
	}
If the hash specified by config is a candidate, we'll use that.
	if  := .Hash(); .Available() {
		for ,  := range  {
			if ,  := s2k.HashIdToHash();  &&  ==  {
				 = 
				break
			}
		}
	}

	if  == 0 {
		 := [0]
		,  := s2k.HashIdToString()
		if ! {
			 = "#" + strconv.Itoa(int())
		}
		return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " +  + " in this case.)")
	}

	if  != nil {
		 := &packet.OnePassSignature{
			SigType:    packet.SigTypeBinary,
			Hash:       ,
			PubKeyAlgo: .PubKeyAlgo,
			KeyId:      .KeyId,
			IsLast:     true,
		}
		if  := .Serialize();  != nil {
			return nil, 
		}
	}

	if  == nil {
		 = &FileHints{}
	}

	 := 
If we need to write a signature packet after the literal data then we need to stop literalData from closing encryptedData.
		 = noOpCloser{}

	}
	var  uint32
	if !.ModTime.IsZero() {
		 = uint32(.ModTime.Unix())
	}
	,  := packet.SerializeLiteral(, .IsBinary, .FileName, )
	if  != nil {
		return nil, 
	}

	if  != nil {
		return signatureWriter{, , , .New(), , }, nil
	}
	return , nil
}
Encrypt encrypts a message to a number of recipients and, optionally, signs it. hints contains optional information, that is also encrypted, that aids the recipients in processing the message. The resulting WriteCloser must be closed after the contents of the file have been written. If config is nil, sensible defaults will be used.
func ( io.Writer,  []*Entity,  *Entity,  *FileHints,  *packet.Config) ( io.WriteCloser,  error) {
	if len() == 0 {
		return nil, errors.InvalidArgumentError("no encryption recipient provided")
	}
These are the possible ciphers that we'll use for the message.
These are the possible hash functions that we'll use for the signature.
In the event that a recipient doesn't specify any supported ciphers or hash functions, these are the ones that we assume that every implementation supports.
	 := [len()-1:]
	 := [len()-1:]

	 := make([]Key, len())
	for  := range  {
		var  bool
		[],  = [].encryptionKey(.Now())
		if ! {
			return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint([].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
		}

		 := [].primaryIdentity().SelfSignature

		 := .PreferredSymmetric
		if len() == 0 {
			 = 
		}
		 := .PreferredHash
		if len() == 0 {
			 = 
		}
		 = intersectPreferences(, )
		 = intersectPreferences(, )
	}

	if len() == 0 || len() == 0 {
		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
	}

If the cipher specified by config is a candidate, we'll use that.
	 := .Cipher()
	for ,  := range  {
		 := packet.CipherFunction()
		if  ==  {
			 = 
			break
		}
	}

	 := make([]byte, .KeySize())
	if ,  := io.ReadFull(.Random(), );  != nil {
		return nil, 
	}

	for ,  := range  {
		if  := packet.SerializeEncryptedKey(, .PublicKey, , , );  != nil {
			return nil, 
		}
	}

	,  := packet.SerializeSymmetricallyEncrypted(, , , )
	if  != nil {
		return
	}

	return writeAndSign(, , , , )
}
Sign signs a message. The resulting WriteCloser must be closed after the contents of the file have been written. hints contains optional information that aids the recipients in processing the message. If config is nil, sensible defaults will be used.
func ( io.Writer,  *Entity,  *FileHints,  *packet.Config) ( io.WriteCloser,  error) {
	if  == nil {
		return nil, errors.InvalidArgumentError("no signer provided")
	}
These are the possible hash functions that we'll use for the signature.
	 := []uint8{
		hashToHashId(crypto.SHA256),
		hashToHashId(crypto.SHA384),
		hashToHashId(crypto.SHA512),
		hashToHashId(crypto.SHA1),
		hashToHashId(crypto.RIPEMD160),
	}
	 := [len()-1:]
	 := .primaryIdentity().SelfSignature.PreferredHash
	if len() == 0 {
		 = 
	}
	 = intersectPreferences(, )
	return writeAndSign(noOpCloser{}, , , , )
}
signatureWriter hashes the contents of a message while passing it along to literalData. When closed, it closes literalData, writes a signature packet to encryptedData and then also closes encryptedData.
type signatureWriter struct {
	encryptedData io.WriteCloser
	literalData   io.WriteCloser
	hashType      crypto.Hash
	h             hash.Hash
	signer        *packet.PrivateKey
	config        *packet.Config
}

func ( signatureWriter) ( []byte) (int, error) {
	.h.Write()
	return .literalData.Write()
}

func ( signatureWriter) () error {
	 := &packet.Signature{
		SigType:      packet.SigTypeBinary,
		PubKeyAlgo:   .signer.PubKeyAlgo,
		Hash:         .hashType,
		CreationTime: .config.Now(),
		IssuerKeyId:  &.signer.KeyId,
	}

	if  := .Sign(.h, .signer, .config);  != nil {
		return 
	}
	if  := .literalData.Close();  != nil {
		return 
	}
	if  := .Serialize(.encryptedData);  != nil {
		return 
	}
	return .encryptedData.Close()
}
noOpCloser is like an ioutil.NopCloser, but for an io.Writer. TODO: we have two of these in OpenPGP packages alone. This probably needs to be promoted somewhere more common.
type noOpCloser struct {
	w io.Writer
}

func ( noOpCloser) ( []byte) ( int,  error) {
	return .w.Write()
}

func ( noOpCloser) () error {
	return nil