mirror of
				https://gitea.com/gitea/tea.git
				synced 2025-10-31 17:25:27 +01:00 
			
		
		
		
	Update Dependencies (#390)
Co-authored-by: Norwin Roosen <git@nroo.de> Co-authored-by: Norwin <git@nroo.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/390 Reviewed-by: 6543 <6543@obermui.de> Reviewed-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Norwin <noerw@noreply.gitea.io> Co-committed-by: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
		
							
								
								
									
										56
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| // Copyright (C) 2019 ProtonTech AG | ||||
|  | ||||
| package packet | ||||
|  | ||||
| import "math/bits" | ||||
|  | ||||
| // AEADConfig collects a number of AEAD parameters along with sensible defaults. | ||||
| // A nil AEADConfig is valid and results in all default values. | ||||
| type AEADConfig struct { | ||||
| 	// The AEAD mode of operation. | ||||
| 	DefaultMode AEADMode | ||||
| 	// Amount of octets in each chunk of data | ||||
| 	ChunkSize uint64 | ||||
| } | ||||
|  | ||||
| // Mode returns the AEAD mode of operation. | ||||
| func (conf *AEADConfig) Mode() AEADMode { | ||||
| 	if conf == nil || conf.DefaultMode == 0 { | ||||
| 		return AEADModeEAX | ||||
| 	} | ||||
| 	mode := conf.DefaultMode | ||||
| 	if mode != AEADModeEAX && mode != AEADModeOCB && | ||||
| 		mode != AEADModeExperimentalGCM { | ||||
| 		panic("AEAD mode unsupported") | ||||
| 	} | ||||
| 	return mode | ||||
| } | ||||
|  | ||||
| // ChunkSizeByte returns the byte indicating the chunk size. The effective | ||||
| // chunk size is computed with the formula uint64(1) << (chunkSizeByte + 6) | ||||
| func (conf *AEADConfig) ChunkSizeByte() byte { | ||||
| 	if conf == nil || conf.ChunkSize == 0 { | ||||
| 		return 12 // 1 << (12 + 6) == 262144 bytes | ||||
| 	} | ||||
|  | ||||
| 	chunkSize := conf.ChunkSize | ||||
| 	exponent := bits.Len64(chunkSize) - 1 | ||||
| 	switch { | ||||
| 	case exponent < 6: | ||||
| 		exponent = 6 | ||||
| 	case exponent > 27: | ||||
| 		exponent = 27 | ||||
| 	} | ||||
|  | ||||
| 	return byte(exponent - 6) | ||||
| } | ||||
|  | ||||
| // decodeAEADChunkSize returns the effective chunk size. In 32-bit systems, the | ||||
| // maximum returned value is 1 << 30. | ||||
| func decodeAEADChunkSize(c byte) int { | ||||
| 	size := uint64(1 << (c + 6)) | ||||
| 	if size != uint64(int(size)) { | ||||
| 		return 1 << 30 | ||||
| 	} | ||||
| 	return int(size) | ||||
| } | ||||
							
								
								
									
										364
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										364
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,364 @@ | ||||
| // Copyright (C) 2019 ProtonTech AG | ||||
|  | ||||
| package packet | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/rand" | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||
| ) | ||||
|  | ||||
| // AEADEncrypted represents an AEAD Encrypted Packet (tag 20, RFC4880bis-5.16). | ||||
| type AEADEncrypted struct { | ||||
| 	cipher        CipherFunction | ||||
| 	mode          AEADMode | ||||
| 	chunkSizeByte byte | ||||
| 	Contents      io.Reader // Encrypted chunks and tags | ||||
| 	initialNonce  []byte    // Referred to as IV in RFC4880-bis | ||||
| } | ||||
|  | ||||
| // Only currently defined version | ||||
| const aeadEncryptedVersion = 1 | ||||
|  | ||||
| // An AEAD opener/sealer, its configuration, and data for en/decryption. | ||||
| type aeadCrypter struct { | ||||
| 	aead           cipher.AEAD | ||||
| 	chunkSize      int | ||||
| 	initialNonce   []byte | ||||
| 	associatedData []byte       // Chunk-independent associated data | ||||
| 	chunkIndex     []byte       // Chunk counter | ||||
| 	bytesProcessed int          // Amount of plaintext bytes encrypted/decrypted | ||||
| 	buffer         bytes.Buffer // Buffered bytes accross chunks | ||||
| } | ||||
|  | ||||
| // aeadEncrypter encrypts and writes bytes. It encrypts when necessary according | ||||
| // to the AEAD block size, and buffers the extra encrypted bytes for next write. | ||||
| type aeadEncrypter struct { | ||||
| 	aeadCrypter                // Embedded plaintext sealer | ||||
| 	writer      io.WriteCloser // 'writer' is a partialLengthWriter | ||||
| } | ||||
|  | ||||
| // aeadDecrypter reads and decrypts bytes. It buffers extra decrypted bytes when | ||||
| // necessary, similar to aeadEncrypter. | ||||
| type aeadDecrypter struct { | ||||
| 	aeadCrypter           // Embedded ciphertext opener | ||||
| 	reader      io.Reader // 'reader' is a partialLengthReader | ||||
| 	peekedBytes []byte    // Used to detect last chunk | ||||
| 	eof         bool | ||||
| } | ||||
|  | ||||
| func (ae *AEADEncrypted) parse(buf io.Reader) error { | ||||
| 	headerData := make([]byte, 4) | ||||
| 	if n, err := io.ReadFull(buf, headerData); n < 4 { | ||||
| 		return errors.AEADError("could not read aead header:" + err.Error()) | ||||
| 	} | ||||
| 	// Read initial nonce | ||||
| 	mode := AEADMode(headerData[2]) | ||||
| 	nonceLen := mode.NonceLength() | ||||
| 	if nonceLen == 0 { | ||||
| 		return errors.AEADError("unknown mode") | ||||
| 	} | ||||
| 	initialNonce := make([]byte, nonceLen) | ||||
| 	if n, err := io.ReadFull(buf, initialNonce); n < nonceLen { | ||||
| 		return errors.AEADError("could not read aead nonce:" + err.Error()) | ||||
| 	} | ||||
| 	ae.Contents = buf | ||||
| 	ae.initialNonce = initialNonce | ||||
| 	c := headerData[1] | ||||
| 	if _, ok := algorithm.CipherById[c]; !ok { | ||||
| 		return errors.UnsupportedError("unknown cipher: " + string(c)) | ||||
| 	} | ||||
| 	ae.cipher = CipherFunction(c) | ||||
| 	ae.mode = mode | ||||
| 	ae.chunkSizeByte = byte(headerData[3]) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Decrypt returns a io.ReadCloser from which decrypted bytes can be read, or | ||||
| // an error. | ||||
| func (ae *AEADEncrypted) Decrypt(ciph CipherFunction, key []byte) (io.ReadCloser, error) { | ||||
| 	return ae.decrypt(key) | ||||
| } | ||||
|  | ||||
| // decrypt prepares an aeadCrypter and returns a ReadCloser from which | ||||
| // decrypted bytes can be read (see aeadDecrypter.Read()). | ||||
| func (ae *AEADEncrypted) decrypt(key []byte) (io.ReadCloser, error) { | ||||
| 	blockCipher := ae.cipher.new(key) | ||||
| 	aead := ae.mode.new(blockCipher) | ||||
| 	// Carry the first tagLen bytes | ||||
| 	tagLen := ae.mode.TagLength() | ||||
| 	peekedBytes := make([]byte, tagLen) | ||||
| 	n, err := io.ReadFull(ae.Contents, peekedBytes) | ||||
| 	if n < tagLen || (err != nil && err != io.EOF) { | ||||
| 		return nil, errors.AEADError("Not enough data to decrypt:" + err.Error()) | ||||
| 	} | ||||
| 	chunkSize := decodeAEADChunkSize(ae.chunkSizeByte) | ||||
| 	return &aeadDecrypter{ | ||||
| 		aeadCrypter: aeadCrypter{ | ||||
| 			aead:           aead, | ||||
| 			chunkSize:      chunkSize, | ||||
| 			initialNonce:   ae.initialNonce, | ||||
| 			associatedData: ae.associatedData(), | ||||
| 			chunkIndex:     make([]byte, 8), | ||||
| 		}, | ||||
| 		reader:      ae.Contents, | ||||
| 		peekedBytes: peekedBytes}, nil | ||||
| } | ||||
|  | ||||
| // Read decrypts bytes and reads them into dst. It decrypts when necessary and | ||||
| // buffers extra decrypted bytes. It returns the number of bytes copied into dst | ||||
| // and an error. | ||||
| func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) { | ||||
| 	// Return buffered plaintext bytes from previous calls | ||||
| 	if ar.buffer.Len() > 0 { | ||||
| 		return ar.buffer.Read(dst) | ||||
| 	} | ||||
|  | ||||
| 	// Return EOF if we've previously validated the final tag | ||||
| 	if ar.eof { | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
|  | ||||
| 	// Read a chunk | ||||
| 	tagLen := ar.aead.Overhead() | ||||
| 	cipherChunkBuf := new(bytes.Buffer) | ||||
| 	_, errRead := io.CopyN(cipherChunkBuf, ar.reader, int64(ar.chunkSize + tagLen)) | ||||
| 	cipherChunk := cipherChunkBuf.Bytes() | ||||
| 	if errRead != nil && errRead != io.EOF { | ||||
| 		return 0, errRead | ||||
| 	} | ||||
| 	decrypted, errChunk := ar.openChunk(cipherChunk) | ||||
| 	if errChunk != nil { | ||||
| 		return 0, errChunk | ||||
| 	} | ||||
|  | ||||
| 	// Return decrypted bytes, buffering if necessary | ||||
| 	if len(dst) < len(decrypted) { | ||||
| 		n = copy(dst, decrypted[:len(dst)]) | ||||
| 		ar.buffer.Write(decrypted[len(dst):]) | ||||
| 	} else { | ||||
| 		n = copy(dst, decrypted) | ||||
| 	} | ||||
|  | ||||
| 	// Check final authentication tag | ||||
| 	if errRead == io.EOF { | ||||
| 		errChunk := ar.validateFinalTag(ar.peekedBytes) | ||||
| 		if errChunk != nil { | ||||
| 			return n, errChunk | ||||
| 		} | ||||
| 		ar.eof = true // Mark EOF for when we've returned all buffered data | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Close is noOp. The final authentication tag of the stream was already | ||||
| // checked in the last Read call. In the future, this function could be used to | ||||
| // wipe the reader and peeked, decrypted bytes, if necessary. | ||||
| func (ar *aeadDecrypter) Close() (err error) { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // SerializeAEADEncrypted initializes the aeadCrypter and returns a writer. | ||||
| // This writer encrypts and writes bytes (see aeadEncrypter.Write()). | ||||
| func SerializeAEADEncrypted(w io.Writer, key []byte, cipher CipherFunction, mode AEADMode, config *Config) (io.WriteCloser, error) { | ||||
| 	writeCloser := noOpCloser{w} | ||||
| 	writer, err := serializeStreamHeader(writeCloser, packetTypeAEADEncrypted) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Data for en/decryption: tag, version, cipher, aead mode, chunk size | ||||
| 	aeadConf := config.AEAD() | ||||
| 	prefix := []byte{ | ||||
| 		0xD4, | ||||
| 		aeadEncryptedVersion, | ||||
| 		byte(config.Cipher()), | ||||
| 		byte(aeadConf.Mode()), | ||||
| 		aeadConf.ChunkSizeByte(), | ||||
| 	} | ||||
| 	n, err := writer.Write(prefix[1:]) | ||||
| 	if err != nil || n < 4 { | ||||
| 		return nil, errors.AEADError("could not write AEAD headers") | ||||
| 	} | ||||
| 	// Sample nonce | ||||
| 	nonceLen := aeadConf.Mode().NonceLength() | ||||
| 	nonce := make([]byte, nonceLen) | ||||
| 	n, err = rand.Read(nonce) | ||||
| 	if err != nil { | ||||
| 		panic("Could not sample random nonce") | ||||
| 	} | ||||
| 	_, err = writer.Write(nonce) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	blockCipher := CipherFunction(config.Cipher()).new(key) | ||||
| 	alg := AEADMode(aeadConf.Mode()).new(blockCipher) | ||||
|  | ||||
| 	chunkSize := decodeAEADChunkSize(aeadConf.ChunkSizeByte()) | ||||
| 	return &aeadEncrypter{ | ||||
| 		aeadCrypter: aeadCrypter{ | ||||
| 			aead:           alg, | ||||
| 			chunkSize:      chunkSize, | ||||
| 			associatedData: prefix, | ||||
| 			chunkIndex:     make([]byte, 8), | ||||
| 			initialNonce:   nonce, | ||||
| 		}, | ||||
| 		writer: writer}, nil | ||||
| } | ||||
|  | ||||
| // Write encrypts and writes bytes. It encrypts when necessary and buffers extra | ||||
| // plaintext bytes for next call. When the stream is finished, Close() MUST be | ||||
| // called to append the final tag. | ||||
| func (aw *aeadEncrypter) Write(plaintextBytes []byte) (n int, err error) { | ||||
| 	// Append plaintextBytes to existing buffered bytes | ||||
| 	n, err = aw.buffer.Write(plaintextBytes) | ||||
| 	if err != nil { | ||||
| 		return n, err | ||||
| 	} | ||||
| 	// Encrypt and write chunks | ||||
| 	for aw.buffer.Len() >= aw.chunkSize { | ||||
| 		plainChunk := aw.buffer.Next(aw.chunkSize) | ||||
| 		encryptedChunk, err := aw.sealChunk(plainChunk) | ||||
| 		if err != nil { | ||||
| 			return n, err | ||||
| 		} | ||||
| 		_, err = aw.writer.Write(encryptedChunk) | ||||
| 		if err != nil { | ||||
| 			return n, err | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Close encrypts and writes the remaining buffered plaintext if any, appends | ||||
| // the final authentication tag, and closes the embedded writer. This function | ||||
| // MUST be called at the end of a stream. | ||||
| func (aw *aeadEncrypter) Close() (err error) { | ||||
| 	// Encrypt and write a chunk if there's buffered data left, or if we haven't | ||||
| 	// written any chunks yet. | ||||
| 	if aw.buffer.Len() > 0 || aw.bytesProcessed == 0 { | ||||
| 		plainChunk := aw.buffer.Bytes() | ||||
| 		lastEncryptedChunk, err := aw.sealChunk(plainChunk) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err = aw.writer.Write(lastEncryptedChunk) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	// Compute final tag (associated data: packet tag, version, cipher, aead, | ||||
| 	// chunk size, index, total number of encrypted octets). | ||||
| 	adata := append(aw.associatedData[:], aw.chunkIndex[:]...) | ||||
| 	adata = append(adata, make([]byte, 8)...) | ||||
| 	binary.BigEndian.PutUint64(adata[13:], uint64(aw.bytesProcessed)) | ||||
| 	nonce := aw.computeNextNonce() | ||||
| 	finalTag := aw.aead.Seal(nil, nonce, nil, adata) | ||||
| 	_, err = aw.writer.Write(finalTag) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return aw.writer.Close() | ||||
| } | ||||
|  | ||||
| // sealChunk Encrypts and authenticates the given chunk. | ||||
| func (aw *aeadEncrypter) sealChunk(data []byte) ([]byte, error) { | ||||
| 	if len(data) > aw.chunkSize { | ||||
| 		return nil, errors.AEADError("chunk exceeds maximum length") | ||||
| 	} | ||||
| 	if aw.associatedData == nil { | ||||
| 		return nil, errors.AEADError("can't seal without headers") | ||||
| 	} | ||||
| 	adata := append(aw.associatedData, aw.chunkIndex...) | ||||
| 	nonce := aw.computeNextNonce() | ||||
| 	encrypted := aw.aead.Seal(nil, nonce, data, adata) | ||||
| 	aw.bytesProcessed += len(data) | ||||
| 	if err := aw.aeadCrypter.incrementIndex(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return encrypted, nil | ||||
| } | ||||
|  | ||||
| // openChunk decrypts and checks integrity of an encrypted chunk, returning | ||||
| // the underlying plaintext and an error. It access peeked bytes from next | ||||
| // chunk, to identify the last chunk and decrypt/validate accordingly. | ||||
| func (ar *aeadDecrypter) openChunk(data []byte) ([]byte, error) { | ||||
| 	tagLen := ar.aead.Overhead() | ||||
| 	// Restore carried bytes from last call | ||||
| 	chunkExtra := append(ar.peekedBytes, data...) | ||||
| 	// 'chunk' contains encrypted bytes, followed by an authentication tag. | ||||
| 	chunk := chunkExtra[:len(chunkExtra)-tagLen] | ||||
| 	ar.peekedBytes = chunkExtra[len(chunkExtra)-tagLen:] | ||||
| 	adata := append(ar.associatedData, ar.chunkIndex...) | ||||
| 	nonce := ar.computeNextNonce() | ||||
| 	plainChunk, err := ar.aead.Open(nil, nonce, chunk, adata) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ar.bytesProcessed += len(plainChunk) | ||||
| 	if err = ar.aeadCrypter.incrementIndex(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return plainChunk, nil | ||||
| } | ||||
|  | ||||
| // Checks the summary tag. It takes into account the total decrypted bytes into | ||||
| // the associated data. It returns an error, or nil if the tag is valid. | ||||
| func (ar *aeadDecrypter) validateFinalTag(tag []byte) error { | ||||
| 	// Associated: tag, version, cipher, aead, chunk size, index, and octets | ||||
| 	amountBytes := make([]byte, 8) | ||||
| 	binary.BigEndian.PutUint64(amountBytes, uint64(ar.bytesProcessed)) | ||||
| 	adata := append(ar.associatedData, ar.chunkIndex...) | ||||
| 	adata = append(adata, amountBytes...) | ||||
| 	nonce := ar.computeNextNonce() | ||||
| 	_, err := ar.aead.Open(nil, nonce, tag, adata) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Associated data for chunks: tag, version, cipher, mode, chunk size byte | ||||
| func (ae *AEADEncrypted) associatedData() []byte { | ||||
| 	return []byte{ | ||||
| 		0xD4, | ||||
| 		aeadEncryptedVersion, | ||||
| 		byte(ae.cipher), | ||||
| 		byte(ae.mode), | ||||
| 		ae.chunkSizeByte} | ||||
| } | ||||
|  | ||||
| // computeNonce takes the incremental index and computes an eXclusive OR with | ||||
| // the least significant 8 bytes of the receivers' initial nonce (see sec. | ||||
| // 5.16.1 and 5.16.2). It returns the resulting nonce. | ||||
| func (wo *aeadCrypter) computeNextNonce() (nonce []byte) { | ||||
| 	nonce = make([]byte, len(wo.initialNonce)) | ||||
| 	copy(nonce, wo.initialNonce) | ||||
| 	offset := len(wo.initialNonce) - 8 | ||||
| 	for i := 0; i < 8; i++ { | ||||
| 		nonce[i+offset] ^= wo.chunkIndex[i] | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // incrementIndex perfoms an integer increment by 1 of the integer represented by the | ||||
| // slice, modifying it accordingly. | ||||
| func (wo *aeadCrypter) incrementIndex() error { | ||||
| 	index := wo.chunkIndex | ||||
| 	if len(index) == 0 { | ||||
| 		return errors.AEADError("Index has length 0") | ||||
| 	} | ||||
| 	for i := len(index) - 1; i >= 0; i-- { | ||||
| 		if index[i] < 255 { | ||||
| 			index[i]++ | ||||
| 			return nil | ||||
| 		} | ||||
| 		index[i] = 0 | ||||
| 	} | ||||
| 	return errors.AEADError("cannot further increment index") | ||||
| } | ||||
							
								
								
									
										123
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"compress/bzip2" | ||||
| 	"compress/flate" | ||||
| 	"compress/zlib" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // Compressed represents a compressed OpenPGP packet. The decompressed contents | ||||
| // will contain more OpenPGP packets. See RFC 4880, section 5.6. | ||||
| type Compressed struct { | ||||
| 	Body io.Reader | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	NoCompression      = flate.NoCompression | ||||
| 	BestSpeed          = flate.BestSpeed | ||||
| 	BestCompression    = flate.BestCompression | ||||
| 	DefaultCompression = flate.DefaultCompression | ||||
| ) | ||||
|  | ||||
| // CompressionConfig contains compressor configuration settings. | ||||
| type CompressionConfig struct { | ||||
| 	// Level is the compression level to use. It must be set to | ||||
| 	// between -1 and 9, with -1 causing the compressor to use the | ||||
| 	// default compression level, 0 causing the compressor to use | ||||
| 	// no compression and 1 to 9 representing increasing (better, | ||||
| 	// slower) compression levels. If Level is less than -1 or | ||||
| 	// more then 9, a non-nil error will be returned during | ||||
| 	// encryption. See the constants above for convenient common | ||||
| 	// settings for Level. | ||||
| 	Level int | ||||
| } | ||||
|  | ||||
| func (c *Compressed) parse(r io.Reader) error { | ||||
| 	var buf [1]byte | ||||
| 	_, err := readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	switch buf[0] { | ||||
| 	case 1: | ||||
| 		c.Body = flate.NewReader(r) | ||||
| 	case 2: | ||||
| 		c.Body, err = zlib.NewReader(r) | ||||
| 	case 3: | ||||
| 		c.Body = bzip2.NewReader(r) | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0]))) | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // compressedWriterCloser represents the serialized compression stream | ||||
| // header and the compressor. Its Close() method ensures that both the | ||||
| // compressor and serialized stream header are closed. Its Write() | ||||
| // method writes to the compressor. | ||||
| type compressedWriteCloser struct { | ||||
| 	sh io.Closer      // Stream Header | ||||
| 	c  io.WriteCloser // Compressor | ||||
| } | ||||
|  | ||||
| func (cwc compressedWriteCloser) Write(p []byte) (int, error) { | ||||
| 	return cwc.c.Write(p) | ||||
| } | ||||
|  | ||||
| func (cwc compressedWriteCloser) Close() (err error) { | ||||
| 	err = cwc.c.Close() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return cwc.sh.Close() | ||||
| } | ||||
|  | ||||
| // SerializeCompressed serializes a compressed data packet to w and | ||||
| // returns a WriteCloser to which the literal data packets themselves | ||||
| // can be written and which MUST be closed on completion. If cc is | ||||
| // nil, sensible defaults will be used to configure the compression | ||||
| // algorithm. | ||||
| func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) { | ||||
| 	compressed, err := serializeStreamHeader(w, packetTypeCompressed) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, err = compressed.Write([]byte{uint8(algo)}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	level := DefaultCompression | ||||
| 	if cc != nil { | ||||
| 		level = cc.Level | ||||
| 	} | ||||
|  | ||||
| 	var compressor io.WriteCloser | ||||
| 	switch algo { | ||||
| 	case CompressionZIP: | ||||
| 		compressor, err = flate.NewWriter(compressed, level) | ||||
| 	case CompressionZLIB: | ||||
| 		compressor, err = zlib.NewWriterLevel(compressed, level) | ||||
| 	default: | ||||
| 		s := strconv.Itoa(int(algo)) | ||||
| 		err = errors.UnsupportedError("Unsupported compression algorithm: " + s) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	literaldata = compressedWriteCloser{compressed, compressor} | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										167
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | ||||
| // Copyright 2012 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"crypto/rand" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Config collects a number of parameters along with sensible defaults. | ||||
| // A nil *Config is valid and results in all default values. | ||||
| type Config struct { | ||||
| 	// Rand provides the source of entropy. | ||||
| 	// If nil, the crypto/rand Reader is used. | ||||
| 	Rand io.Reader | ||||
| 	// DefaultHash is the default hash function to be used. | ||||
| 	// If zero, SHA-256 is used. | ||||
| 	DefaultHash crypto.Hash | ||||
| 	// DefaultCipher is the cipher to be used. | ||||
| 	// If zero, AES-128 is used. | ||||
| 	DefaultCipher CipherFunction | ||||
| 	// Time returns the current time as the number of seconds since the | ||||
| 	// epoch. If Time is nil, time.Now is used. | ||||
| 	Time func() time.Time | ||||
| 	// DefaultCompressionAlgo is the compression algorithm to be | ||||
| 	// applied to the plaintext before encryption. If zero, no | ||||
| 	// compression is done. | ||||
| 	DefaultCompressionAlgo CompressionAlgo | ||||
| 	// CompressionConfig configures the compression settings. | ||||
| 	CompressionConfig *CompressionConfig | ||||
| 	// S2KCount is only used for symmetric encryption. It | ||||
| 	// determines the strength of the passphrase stretching when | ||||
| 	// the said passphrase is hashed to produce a key. S2KCount | ||||
| 	// should be between 1024 and 65011712, inclusive. If Config | ||||
| 	// is nil or S2KCount is 0, the value 65536 used. Not all | ||||
| 	// values in the above range can be represented. S2KCount will | ||||
| 	// be rounded up to the next representable value if it cannot | ||||
| 	// be encoded exactly. When set, it is strongly encrouraged to | ||||
| 	// use a value that is at least 65536. See RFC 4880 Section | ||||
| 	// 3.7.1.3. | ||||
| 	S2KCount int | ||||
| 	// RSABits is the number of bits in new RSA keys made with NewEntity. | ||||
| 	// If zero, then 2048 bit keys are created. | ||||
| 	RSABits int | ||||
| 	// The public key algorithm to use - will always create a signing primary | ||||
| 	// key and encryption subkey. | ||||
| 	Algorithm PublicKeyAlgorithm | ||||
| 	// Some known primes that are optionally prepopulated by the caller | ||||
| 	RSAPrimes []*big.Int | ||||
| 	// AEADConfig configures the use of the new AEAD Encrypted Data Packet, | ||||
| 	// defined in the draft of the next version of the OpenPGP specification. | ||||
| 	// If a non-nil AEADConfig is passed, usage of this packet is enabled. By | ||||
| 	// default, it is disabled. See the documentation of AEADConfig for more | ||||
| 	// configuration options related to AEAD. | ||||
| 	// **Note: using this option may break compatibility with other OpenPGP | ||||
| 	// implementations, as well as future versions of this library.** | ||||
| 	AEADConfig *AEADConfig | ||||
| 	// V5Keys configures version 5 key generation. If false, this package still | ||||
| 	// supports version 5 keys, but produces version 4 keys. | ||||
| 	V5Keys bool | ||||
| 	// "The validity period of the key.  This is the number of seconds after | ||||
| 	// the key creation time that the key expires.  If this is not present | ||||
| 	// or has a value of zero, the key never expires.  This is found only on | ||||
| 	// a self-signature."" | ||||
| 	// https://tools.ietf.org/html/rfc4880#section-5.2.3.6 | ||||
| 	KeyLifetimeSecs uint32 | ||||
| 	// "The validity period of the signature.  This is the number of seconds | ||||
| 	// after the signature creation time that the signature expires.  If | ||||
| 	// this is not present or has a value of zero, it never expires." | ||||
| 	// https://tools.ietf.org/html/rfc4880#section-5.2.3.10 | ||||
| 	SigLifetimeSecs uint32 | ||||
| 	// SigningKeyId is used to specify the signing key to use (by Key ID). | ||||
| 	// By default, the signing key is selected automatically, preferring | ||||
| 	// signing subkeys if available. | ||||
| 	SigningKeyId uint64 | ||||
| } | ||||
|  | ||||
| func (c *Config) Random() io.Reader { | ||||
| 	if c == nil || c.Rand == nil { | ||||
| 		return rand.Reader | ||||
| 	} | ||||
| 	return c.Rand | ||||
| } | ||||
|  | ||||
| func (c *Config) Hash() crypto.Hash { | ||||
| 	if c == nil || uint(c.DefaultHash) == 0 { | ||||
| 		return crypto.SHA256 | ||||
| 	} | ||||
| 	return c.DefaultHash | ||||
| } | ||||
|  | ||||
| func (c *Config) Cipher() CipherFunction { | ||||
| 	if c == nil || uint8(c.DefaultCipher) == 0 { | ||||
| 		return CipherAES128 | ||||
| 	} | ||||
| 	return c.DefaultCipher | ||||
| } | ||||
|  | ||||
| func (c *Config) Now() time.Time { | ||||
| 	if c == nil || c.Time == nil { | ||||
| 		return time.Now() | ||||
| 	} | ||||
| 	return c.Time() | ||||
| } | ||||
|  | ||||
| // KeyLifetime returns the validity period of the key. | ||||
| func (c *Config) KeyLifetime() uint32 { | ||||
| 	if c == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return c.KeyLifetimeSecs | ||||
| } | ||||
|  | ||||
| // SigLifetime returns the validity period of the signature. | ||||
| func (c *Config) SigLifetime() uint32 { | ||||
| 	if c == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return c.SigLifetimeSecs | ||||
| } | ||||
|  | ||||
| func (c *Config) Compression() CompressionAlgo { | ||||
| 	if c == nil { | ||||
| 		return CompressionNone | ||||
| 	} | ||||
| 	return c.DefaultCompressionAlgo | ||||
| } | ||||
|  | ||||
| func (c *Config) PasswordHashIterations() int { | ||||
| 	if c == nil || c.S2KCount == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return c.S2KCount | ||||
| } | ||||
|  | ||||
| func (c *Config) RSAModulusBits() int { | ||||
| 	if c == nil || c.RSABits == 0 { | ||||
| 		return 2048 | ||||
| 	} | ||||
| 	return c.RSABits | ||||
| } | ||||
|  | ||||
| func (c *Config) PublicKeyAlgorithm() PublicKeyAlgorithm { | ||||
| 	if c == nil || c.Algorithm == 0 { | ||||
| 		return PubKeyAlgoRSA | ||||
| 	} | ||||
| 	return c.Algorithm | ||||
| } | ||||
|  | ||||
| func (c *Config) AEAD() *AEADConfig { | ||||
| 	if c == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return c.AEADConfig | ||||
| } | ||||
|  | ||||
| func (c *Config) SigningKey() uint64 { | ||||
| 	if c == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return c.SigningKeyId | ||||
| } | ||||
							
								
								
									
										282
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,282 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"crypto/rsa" | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/elgamal" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||
| ) | ||||
|  | ||||
| const encryptedKeyVersion = 3 | ||||
|  | ||||
| // EncryptedKey represents a public-key encrypted session key. See RFC 4880, | ||||
| // section 5.1. | ||||
| type EncryptedKey struct { | ||||
| 	KeyId      uint64 | ||||
| 	Algo       PublicKeyAlgorithm | ||||
| 	CipherFunc CipherFunction // only valid after a successful Decrypt | ||||
| 	Key        []byte         // only valid after a successful Decrypt | ||||
|  | ||||
| 	encryptedMPI1, encryptedMPI2 encoding.Field | ||||
| } | ||||
|  | ||||
| func (e *EncryptedKey) parse(r io.Reader) (err error) { | ||||
| 	var buf [10]byte | ||||
| 	_, err = readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] != encryptedKeyVersion { | ||||
| 		return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0]))) | ||||
| 	} | ||||
| 	e.KeyId = binary.BigEndian.Uint64(buf[1:9]) | ||||
| 	e.Algo = PublicKeyAlgorithm(buf[9]) | ||||
| 	switch e.Algo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||
| 		e.encryptedMPI1 = new(encoding.MPI) | ||||
| 		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		e.encryptedMPI1 = new(encoding.MPI) | ||||
| 		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		e.encryptedMPI2 = new(encoding.MPI) | ||||
| 		if _, err = e.encryptedMPI2.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		e.encryptedMPI1 = new(encoding.MPI) | ||||
| 		if _, err = e.encryptedMPI1.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		e.encryptedMPI2 = new(encoding.OID) | ||||
| 		if _, err = e.encryptedMPI2.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	_, err = consumeAll(r) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func checksumKeyMaterial(key []byte) uint16 { | ||||
| 	var checksum uint16 | ||||
| 	for _, v := range key { | ||||
| 		checksum += uint16(v) | ||||
| 	} | ||||
| 	return checksum | ||||
| } | ||||
|  | ||||
| // Decrypt decrypts an encrypted session key with the given private key. The | ||||
| // private key must have been decrypted first. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { | ||||
| 	if e.KeyId != 0 && e.KeyId != priv.KeyId { | ||||
| 		return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16)) | ||||
| 	} | ||||
| 	if e.Algo != priv.PubKeyAlgo { | ||||
| 		return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) | ||||
| 	} | ||||
| 	if priv.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var b []byte | ||||
|  | ||||
| 	// TODO(agl): use session key decryption routines here to avoid | ||||
| 	// padding oracle attacks. | ||||
| 	switch priv.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||
| 		// Supports both *rsa.PrivateKey and crypto.Decrypter | ||||
| 		k := priv.PrivateKey.(crypto.Decrypter) | ||||
| 		b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.Bytes()), nil) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		c1 := new(big.Int).SetBytes(e.encryptedMPI1.Bytes()) | ||||
| 		c2 := new(big.Int).SetBytes(e.encryptedMPI2.Bytes()) | ||||
| 		b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		vsG := e.encryptedMPI1.Bytes() | ||||
| 		m := e.encryptedMPI2.Bytes() | ||||
| 		oid := priv.PublicKey.oid.EncodedBytes() | ||||
| 		b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, priv.PublicKey.Fingerprint[:]) | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	e.CipherFunc = CipherFunction(b[0]) | ||||
| 	e.Key = b[1 : len(b)-2] | ||||
| 	expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) | ||||
| 	checksum := checksumKeyMaterial(e.Key) | ||||
| 	if checksum != expectedChecksum { | ||||
| 		return errors.StructuralError("EncryptedKey checksum incorrect") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Serialize writes the encrypted key packet, e, to w. | ||||
| func (e *EncryptedKey) Serialize(w io.Writer) error { | ||||
| 	var mpiLen int | ||||
| 	switch e.Algo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||
| 		mpiLen = int(e.encryptedMPI1.EncodedLength()) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength()) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength()) | ||||
| 	default: | ||||
| 		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) | ||||
| 	} | ||||
|  | ||||
| 	err := serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	w.Write([]byte{encryptedKeyVersion}) | ||||
| 	binary.Write(w, binary.BigEndian, e.KeyId) | ||||
| 	w.Write([]byte{byte(e.Algo)}) | ||||
|  | ||||
| 	switch e.Algo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||
| 		_, err := w.Write(e.encryptedMPI1.EncodedBytes()) | ||||
| 		return err | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err := w.Write(e.encryptedMPI2.EncodedBytes()) | ||||
| 		return err | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		if _, err := w.Write(e.encryptedMPI1.EncodedBytes()); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err := w.Write(e.encryptedMPI2.EncodedBytes()) | ||||
| 		return err | ||||
| 	default: | ||||
| 		panic("internal error") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SerializeEncryptedKey serializes an encrypted key packet to w that contains | ||||
| // key, encrypted to pub. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error { | ||||
| 	var buf [10]byte | ||||
| 	buf[0] = encryptedKeyVersion | ||||
| 	binary.BigEndian.PutUint64(buf[1:9], pub.KeyId) | ||||
| 	buf[9] = byte(pub.PubKeyAlgo) | ||||
|  | ||||
| 	keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */) | ||||
| 	keyBlock[0] = byte(cipherFunc) | ||||
| 	copy(keyBlock[1:], key) | ||||
| 	checksum := checksumKeyMaterial(key) | ||||
| 	keyBlock[1+len(key)] = byte(checksum >> 8) | ||||
| 	keyBlock[1+len(key)+1] = byte(checksum) | ||||
|  | ||||
| 	switch pub.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||
| 		return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		return serializeEncryptedKeyECDH(w, config.Random(), buf, pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint) | ||||
| 	case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: | ||||
| 		return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) | ||||
| 	} | ||||
|  | ||||
| 	return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) | ||||
| } | ||||
|  | ||||
| func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error { | ||||
| 	cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock) | ||||
| 	if err != nil { | ||||
| 		return errors.InvalidArgumentError("RSA encryption failed: " + err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	cipherMPI := encoding.NewMPI(cipherText) | ||||
| 	packetLen := 10 /* header length */ + int(cipherMPI.EncodedLength()) | ||||
|  | ||||
| 	err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(header[:]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(cipherMPI.EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error { | ||||
| 	c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock) | ||||
| 	if err != nil { | ||||
| 		return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	packetLen := 10 /* header length */ | ||||
| 	packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8 | ||||
| 	packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8 | ||||
|  | ||||
| 	err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(header[:]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err = w.Write(new(encoding.MPI).SetBig(c1).EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(new(encoding.MPI).SetBig(c2).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error { | ||||
| 	vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint) | ||||
| 	if err != nil { | ||||
| 		return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	g := encoding.NewMPI(vsG) | ||||
| 	m := encoding.NewOID(c) | ||||
|  | ||||
| 	packetLen := 10 /* header length */ | ||||
| 	packetLen += int(g.EncodedLength()) + int(m.EncodedLength()) | ||||
|  | ||||
| 	err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = w.Write(header[:]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err = w.Write(g.EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(m.EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| // LiteralData represents an encrypted file. See RFC 4880, section 5.9. | ||||
| type LiteralData struct { | ||||
| 	Format   uint8 | ||||
| 	IsBinary bool | ||||
| 	FileName string | ||||
| 	Time     uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined. | ||||
| 	Body     io.Reader | ||||
| } | ||||
|  | ||||
| // ForEyesOnly returns whether the contents of the LiteralData have been marked | ||||
| // as especially sensitive. | ||||
| func (l *LiteralData) ForEyesOnly() bool { | ||||
| 	return l.FileName == "_CONSOLE" | ||||
| } | ||||
|  | ||||
| func (l *LiteralData) parse(r io.Reader) (err error) { | ||||
| 	var buf [256]byte | ||||
|  | ||||
| 	_, err = readFull(r, buf[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	l.Format = buf[0] | ||||
| 	l.IsBinary = l.Format == 'b' | ||||
| 	fileNameLen := int(buf[1]) | ||||
|  | ||||
| 	_, err = readFull(r, buf[:fileNameLen]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	l.FileName = string(buf[:fileNameLen]) | ||||
|  | ||||
| 	_, err = readFull(r, buf[:4]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	l.Time = binary.BigEndian.Uint32(buf[:4]) | ||||
| 	l.Body = r | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // SerializeLiteral serializes a literal data packet to w and returns a | ||||
| // WriteCloser to which the data itself can be written and which MUST be closed | ||||
| // on completion. The fileName is truncated to 255 bytes. | ||||
| func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) { | ||||
| 	var buf [4]byte | ||||
| 	buf[0] = 't' | ||||
| 	if isBinary { | ||||
| 		buf[0] = 'b' | ||||
| 	} | ||||
| 	if len(fileName) > 255 { | ||||
| 		fileName = fileName[:255] | ||||
| 	} | ||||
| 	buf[1] = byte(len(fileName)) | ||||
|  | ||||
| 	inner, err := serializeStreamHeader(w, packetTypeLiteralData) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, err = inner.Write(buf[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = inner.Write([]byte(fileName)) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	binary.BigEndian.PutUint32(buf[:], time) | ||||
| 	_, err = inner.Write(buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	plaintext = inner | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										137
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/ocfb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| // Copyright 2010 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. | ||||
|  | ||||
| // OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9 | ||||
|  | ||||
| package packet | ||||
|  | ||||
| import ( | ||||
| 	"crypto/cipher" | ||||
| ) | ||||
|  | ||||
| type ocfbEncrypter struct { | ||||
| 	b       cipher.Block | ||||
| 	fre     []byte | ||||
| 	outUsed int | ||||
| } | ||||
|  | ||||
| // An OCFBResyncOption determines if the "resynchronization step" of OCFB is | ||||
| // performed. | ||||
| type OCFBResyncOption bool | ||||
|  | ||||
| const ( | ||||
| 	OCFBResync   OCFBResyncOption = true | ||||
| 	OCFBNoResync OCFBResyncOption = false | ||||
| ) | ||||
|  | ||||
| // NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's | ||||
| // cipher feedback mode using the given cipher.Block, and an initial amount of | ||||
| // ciphertext.  randData must be random bytes and be the same length as the | ||||
| // cipher.Block's block size. Resync determines if the "resynchronization step" | ||||
| // from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on | ||||
| // this point. | ||||
| func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) { | ||||
| 	blockSize := block.BlockSize() | ||||
| 	if len(randData) != blockSize { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	x := &ocfbEncrypter{ | ||||
| 		b:       block, | ||||
| 		fre:     make([]byte, blockSize), | ||||
| 		outUsed: 0, | ||||
| 	} | ||||
| 	prefix := make([]byte, blockSize+2) | ||||
|  | ||||
| 	block.Encrypt(x.fre, x.fre) | ||||
| 	for i := 0; i < blockSize; i++ { | ||||
| 		prefix[i] = randData[i] ^ x.fre[i] | ||||
| 	} | ||||
|  | ||||
| 	block.Encrypt(x.fre, prefix[:blockSize]) | ||||
| 	prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] | ||||
| 	prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] | ||||
|  | ||||
| 	if resync { | ||||
| 		block.Encrypt(x.fre, prefix[2:]) | ||||
| 	} else { | ||||
| 		x.fre[0] = prefix[blockSize] | ||||
| 		x.fre[1] = prefix[blockSize+1] | ||||
| 		x.outUsed = 2 | ||||
| 	} | ||||
| 	return x, prefix | ||||
| } | ||||
|  | ||||
| func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) { | ||||
| 	for i := 0; i < len(src); i++ { | ||||
| 		if x.outUsed == len(x.fre) { | ||||
| 			x.b.Encrypt(x.fre, x.fre) | ||||
| 			x.outUsed = 0 | ||||
| 		} | ||||
|  | ||||
| 		x.fre[x.outUsed] ^= src[i] | ||||
| 		dst[i] = x.fre[x.outUsed] | ||||
| 		x.outUsed++ | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type ocfbDecrypter struct { | ||||
| 	b       cipher.Block | ||||
| 	fre     []byte | ||||
| 	outUsed int | ||||
| } | ||||
|  | ||||
| // NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's | ||||
| // cipher feedback mode using the given cipher.Block. Prefix must be the first | ||||
| // blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's | ||||
| // block size. On successful exit, blockSize+2 bytes of decrypted data are written into | ||||
| // prefix. Resync determines if the "resynchronization step" from RFC 4880, | ||||
| // 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. | ||||
| func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { | ||||
| 	blockSize := block.BlockSize() | ||||
| 	if len(prefix) != blockSize+2 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	x := &ocfbDecrypter{ | ||||
| 		b:       block, | ||||
| 		fre:     make([]byte, blockSize), | ||||
| 		outUsed: 0, | ||||
| 	} | ||||
| 	prefixCopy := make([]byte, len(prefix)) | ||||
| 	copy(prefixCopy, prefix) | ||||
|  | ||||
| 	block.Encrypt(x.fre, x.fre) | ||||
| 	for i := 0; i < blockSize; i++ { | ||||
| 		prefixCopy[i] ^= x.fre[i] | ||||
| 	} | ||||
|  | ||||
| 	block.Encrypt(x.fre, prefix[:blockSize]) | ||||
| 	prefixCopy[blockSize] ^= x.fre[0] | ||||
| 	prefixCopy[blockSize+1] ^= x.fre[1] | ||||
|  | ||||
| 	if resync { | ||||
| 		block.Encrypt(x.fre, prefix[2:]) | ||||
| 	} else { | ||||
| 		x.fre[0] = prefix[blockSize] | ||||
| 		x.fre[1] = prefix[blockSize+1] | ||||
| 		x.outUsed = 2 | ||||
| 	} | ||||
| 	copy(prefix, prefixCopy) | ||||
| 	return x | ||||
| } | ||||
|  | ||||
| func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) { | ||||
| 	for i := 0; i < len(src); i++ { | ||||
| 		if x.outUsed == len(x.fre) { | ||||
| 			x.b.Encrypt(x.fre, x.fre) | ||||
| 			x.outUsed = 0 | ||||
| 		} | ||||
|  | ||||
| 		c := src[i] | ||||
| 		dst[i] = x.fre[x.outUsed] ^ src[i] | ||||
| 		x.fre[x.outUsed] = c | ||||
| 		x.outUsed++ | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										73
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"encoding/binary" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // OnePassSignature represents a one-pass signature packet. See RFC 4880, | ||||
| // section 5.4. | ||||
| type OnePassSignature struct { | ||||
| 	SigType    SignatureType | ||||
| 	Hash       crypto.Hash | ||||
| 	PubKeyAlgo PublicKeyAlgorithm | ||||
| 	KeyId      uint64 | ||||
| 	IsLast     bool | ||||
| } | ||||
|  | ||||
| const onePassSignatureVersion = 3 | ||||
|  | ||||
| func (ops *OnePassSignature) parse(r io.Reader) (err error) { | ||||
| 	var buf [13]byte | ||||
|  | ||||
| 	_, err = readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] != onePassSignatureVersion { | ||||
| 		err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0]))) | ||||
| 	} | ||||
|  | ||||
| 	var ok bool | ||||
| 	ops.Hash, ok = s2k.HashIdToHash(buf[2]) | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2]))) | ||||
| 	} | ||||
|  | ||||
| 	ops.SigType = SignatureType(buf[1]) | ||||
| 	ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3]) | ||||
| 	ops.KeyId = binary.BigEndian.Uint64(buf[4:12]) | ||||
| 	ops.IsLast = buf[12] != 0 | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Serialize marshals the given OnePassSignature to w. | ||||
| func (ops *OnePassSignature) Serialize(w io.Writer) error { | ||||
| 	var buf [13]byte | ||||
| 	buf[0] = onePassSignatureVersion | ||||
| 	buf[1] = uint8(ops.SigType) | ||||
| 	var ok bool | ||||
| 	buf[2], ok = s2k.HashToHashId(ops.Hash) | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash))) | ||||
| 	} | ||||
| 	buf[3] = uint8(ops.PubKeyAlgo) | ||||
| 	binary.BigEndian.PutUint64(buf[4:12], ops.KeyId) | ||||
| 	if ops.IsLast { | ||||
| 		buf[12] = 1 | ||||
| 	} | ||||
|  | ||||
| 	if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err := w.Write(buf[:]) | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										162
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| // Copyright 2012 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| ) | ||||
|  | ||||
| // OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is | ||||
| // useful for splitting and storing the original packet contents separately, | ||||
| // handling unsupported packet types or accessing parts of the packet not yet | ||||
| // implemented by this package. | ||||
| type OpaquePacket struct { | ||||
| 	// Packet type | ||||
| 	Tag uint8 | ||||
| 	// Reason why the packet was parsed opaquely | ||||
| 	Reason error | ||||
| 	// Binary contents of the packet data | ||||
| 	Contents []byte | ||||
| } | ||||
|  | ||||
| func (op *OpaquePacket) parse(r io.Reader) (err error) { | ||||
| 	op.Contents, err = ioutil.ReadAll(r) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Serialize marshals the packet to a writer in its original form, including | ||||
| // the packet header. | ||||
| func (op *OpaquePacket) Serialize(w io.Writer) (err error) { | ||||
| 	err = serializeHeader(w, packetType(op.Tag), len(op.Contents)) | ||||
| 	if err == nil { | ||||
| 		_, err = w.Write(op.Contents) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Parse attempts to parse the opaque contents into a structure supported by | ||||
| // this package. If the packet is not known then the result will be another | ||||
| // OpaquePacket. | ||||
| func (op *OpaquePacket) Parse() (p Packet, err error) { | ||||
| 	hdr := bytes.NewBuffer(nil) | ||||
| 	err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents)) | ||||
| 	if err != nil { | ||||
| 		op.Reason = err | ||||
| 		return op, err | ||||
| 	} | ||||
| 	p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents))) | ||||
| 	if err != nil { | ||||
| 		op.Reason = err | ||||
| 		p = op | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // OpaqueReader reads OpaquePackets from an io.Reader. | ||||
| type OpaqueReader struct { | ||||
| 	r io.Reader | ||||
| } | ||||
|  | ||||
| func NewOpaqueReader(r io.Reader) *OpaqueReader { | ||||
| 	return &OpaqueReader{r: r} | ||||
| } | ||||
|  | ||||
| // Read the next OpaquePacket. | ||||
| func (or *OpaqueReader) Next() (op *OpaquePacket, err error) { | ||||
| 	tag, _, contents, err := readHeader(or.r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	op = &OpaquePacket{Tag: uint8(tag), Reason: err} | ||||
| 	err = op.parse(contents) | ||||
| 	if err != nil { | ||||
| 		consumeAll(contents) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // OpaqueSubpacket represents an unparsed OpenPGP subpacket, | ||||
| // as found in signature and user attribute packets. | ||||
| type OpaqueSubpacket struct { | ||||
| 	SubType  uint8 | ||||
| 	Contents []byte | ||||
| } | ||||
|  | ||||
| // OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from | ||||
| // their byte representation. | ||||
| func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) { | ||||
| 	var ( | ||||
| 		subHeaderLen int | ||||
| 		subPacket    *OpaqueSubpacket | ||||
| 	) | ||||
| 	for len(contents) > 0 { | ||||
| 		subHeaderLen, subPacket, err = nextSubpacket(contents) | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		result = append(result, subPacket) | ||||
| 		contents = contents[subHeaderLen+len(subPacket.Contents):] | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) { | ||||
| 	// RFC 4880, section 5.2.3.1 | ||||
| 	var subLen uint32 | ||||
| 	if len(contents) < 1 { | ||||
| 		goto Truncated | ||||
| 	} | ||||
| 	subPacket = &OpaqueSubpacket{} | ||||
| 	switch { | ||||
| 	case contents[0] < 192: | ||||
| 		subHeaderLen = 2 // 1 length byte, 1 subtype byte | ||||
| 		if len(contents) < subHeaderLen { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		subLen = uint32(contents[0]) | ||||
| 		contents = contents[1:] | ||||
| 	case contents[0] < 255: | ||||
| 		subHeaderLen = 3 // 2 length bytes, 1 subtype | ||||
| 		if len(contents) < subHeaderLen { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192 | ||||
| 		contents = contents[2:] | ||||
| 	default: | ||||
| 		subHeaderLen = 6 // 5 length bytes, 1 subtype | ||||
| 		if len(contents) < subHeaderLen { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		subLen = uint32(contents[1])<<24 | | ||||
| 			uint32(contents[2])<<16 | | ||||
| 			uint32(contents[3])<<8 | | ||||
| 			uint32(contents[4]) | ||||
| 		contents = contents[5:] | ||||
| 	} | ||||
| 	if subLen > uint32(len(contents)) || subLen == 0 { | ||||
| 		goto Truncated | ||||
| 	} | ||||
| 	subPacket.SubType = contents[0] | ||||
| 	subPacket.Contents = contents[1:subLen] | ||||
| 	return | ||||
| Truncated: | ||||
| 	err = errors.StructuralError("subpacket truncated") | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) { | ||||
| 	buf := make([]byte, 6) | ||||
| 	n := serializeSubpacketLength(buf, len(osp.Contents)+1) | ||||
| 	buf[n] = osp.SubType | ||||
| 	if _, err = w.Write(buf[:n+1]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(osp.Contents) | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										522
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										522
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,522 @@ | ||||
| // 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 packet implements parsing and serialization of OpenPGP packets, as | ||||
| // specified in RFC 4880. | ||||
| package packet // import "github.com/ProtonMail/go-crypto/openpgp/packet" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/rsa" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||
| ) | ||||
|  | ||||
| // readFull is the same as io.ReadFull except that reading zero bytes returns | ||||
| // ErrUnexpectedEOF rather than EOF. | ||||
| func readFull(r io.Reader, buf []byte) (n int, err error) { | ||||
| 	n, err = io.ReadFull(r, buf) | ||||
| 	if err == io.EOF { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2. | ||||
| func readLength(r io.Reader) (length int64, isPartial bool, err error) { | ||||
| 	var buf [4]byte | ||||
| 	_, err = readFull(r, buf[:1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	switch { | ||||
| 	case buf[0] < 192: | ||||
| 		length = int64(buf[0]) | ||||
| 	case buf[0] < 224: | ||||
| 		length = int64(buf[0]-192) << 8 | ||||
| 		_, err = readFull(r, buf[0:1]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		length += int64(buf[0]) + 192 | ||||
| 	case buf[0] < 255: | ||||
| 		length = int64(1) << (buf[0] & 0x1f) | ||||
| 		isPartial = true | ||||
| 	default: | ||||
| 		_, err = readFull(r, buf[0:4]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		length = int64(buf[0])<<24 | | ||||
| 			int64(buf[1])<<16 | | ||||
| 			int64(buf[2])<<8 | | ||||
| 			int64(buf[3]) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths. | ||||
| // The continuation lengths are parsed and removed from the stream and EOF is | ||||
| // returned at the end of the packet. See RFC 4880, section 4.2.2.4. | ||||
| type partialLengthReader struct { | ||||
| 	r         io.Reader | ||||
| 	remaining int64 | ||||
| 	isPartial bool | ||||
| } | ||||
|  | ||||
| func (r *partialLengthReader) Read(p []byte) (n int, err error) { | ||||
| 	for r.remaining == 0 { | ||||
| 		if !r.isPartial { | ||||
| 			return 0, io.EOF | ||||
| 		} | ||||
| 		r.remaining, r.isPartial, err = readLength(r.r) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	toRead := int64(len(p)) | ||||
| 	if toRead > r.remaining { | ||||
| 		toRead = r.remaining | ||||
| 	} | ||||
|  | ||||
| 	n, err = r.r.Read(p[:int(toRead)]) | ||||
| 	r.remaining -= int64(n) | ||||
| 	if n < int(toRead) && err == io.EOF { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // partialLengthWriter writes a stream of data using OpenPGP partial lengths. | ||||
| // See RFC 4880, section 4.2.2.4. | ||||
| type partialLengthWriter struct { | ||||
| 	w          io.WriteCloser | ||||
| 	buf        bytes.Buffer | ||||
| 	lengthByte [1]byte | ||||
| } | ||||
|  | ||||
| func (w *partialLengthWriter) Write(p []byte) (n int, err error) { | ||||
| 	bufLen := w.buf.Len() | ||||
| 	if bufLen > 512 { | ||||
| 		for power := uint(30); ; power-- { | ||||
| 			l := 1 << power | ||||
| 			if bufLen >= l { | ||||
| 				w.lengthByte[0] = 224 + uint8(power) | ||||
| 				_, err = w.w.Write(w.lengthByte[:]) | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				var m int | ||||
| 				m, err = w.w.Write(w.buf.Next(l)) | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if m != l { | ||||
| 					return 0, io.ErrShortWrite | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return w.buf.Write(p) | ||||
| } | ||||
|  | ||||
| func (w *partialLengthWriter) Close() (err error) { | ||||
| 	len := w.buf.Len() | ||||
| 	err = serializeLength(w.w, len) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.buf.WriteTo(w.w) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return w.w.Close() | ||||
| } | ||||
|  | ||||
| // A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the | ||||
| // underlying Reader returns EOF before the limit has been reached. | ||||
| type spanReader struct { | ||||
| 	r io.Reader | ||||
| 	n int64 | ||||
| } | ||||
|  | ||||
| func (l *spanReader) Read(p []byte) (n int, err error) { | ||||
| 	if l.n <= 0 { | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
| 	if int64(len(p)) > l.n { | ||||
| 		p = p[0:l.n] | ||||
| 	} | ||||
| 	n, err = l.r.Read(p) | ||||
| 	l.n -= int64(n) | ||||
| 	if l.n > 0 && err == io.EOF { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // readHeader parses a packet header and returns an io.Reader which will return | ||||
| // the contents of the packet. See RFC 4880, section 4.2. | ||||
| func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) { | ||||
| 	var buf [4]byte | ||||
| 	_, err = io.ReadFull(r, buf[:1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0]&0x80 == 0 { | ||||
| 		err = errors.StructuralError("tag byte does not have MSB set") | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0]&0x40 == 0 { | ||||
| 		// Old format packet | ||||
| 		tag = packetType((buf[0] & 0x3f) >> 2) | ||||
| 		lengthType := buf[0] & 3 | ||||
| 		if lengthType == 3 { | ||||
| 			length = -1 | ||||
| 			contents = r | ||||
| 			return | ||||
| 		} | ||||
| 		lengthBytes := 1 << lengthType | ||||
| 		_, err = readFull(r, buf[0:lengthBytes]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		for i := 0; i < lengthBytes; i++ { | ||||
| 			length <<= 8 | ||||
| 			length |= int64(buf[i]) | ||||
| 		} | ||||
| 		contents = &spanReader{r, length} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// New format packet | ||||
| 	tag = packetType(buf[0] & 0x3f) | ||||
| 	length, isPartial, err := readLength(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if isPartial { | ||||
| 		contents = &partialLengthReader{ | ||||
| 			remaining: length, | ||||
| 			isPartial: true, | ||||
| 			r:         r, | ||||
| 		} | ||||
| 		length = -1 | ||||
| 	} else { | ||||
| 		contents = &spanReader{r, length} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section | ||||
| // 4.2. | ||||
| func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { | ||||
| 	err = serializeType(w, ptype) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return serializeLength(w, length) | ||||
| } | ||||
|  | ||||
| // serializeType writes an OpenPGP packet type to w. See RFC 4880, section | ||||
| // 4.2. | ||||
| func serializeType(w io.Writer, ptype packetType) (err error) { | ||||
| 	var buf [1]byte | ||||
| 	buf[0] = 0x80 | 0x40 | byte(ptype) | ||||
| 	_, err = w.Write(buf[:]) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // serializeLength writes an OpenPGP packet length to w. See RFC 4880, section | ||||
| // 4.2.2. | ||||
| func serializeLength(w io.Writer, length int) (err error) { | ||||
| 	var buf [5]byte | ||||
| 	var n int | ||||
|  | ||||
| 	if length < 192 { | ||||
| 		buf[0] = byte(length) | ||||
| 		n = 1 | ||||
| 	} else if length < 8384 { | ||||
| 		length -= 192 | ||||
| 		buf[0] = 192 + byte(length>>8) | ||||
| 		buf[1] = byte(length) | ||||
| 		n = 2 | ||||
| 	} else { | ||||
| 		buf[0] = 255 | ||||
| 		buf[1] = byte(length >> 24) | ||||
| 		buf[2] = byte(length >> 16) | ||||
| 		buf[3] = byte(length >> 8) | ||||
| 		buf[4] = byte(length) | ||||
| 		n = 5 | ||||
| 	} | ||||
|  | ||||
| 	_, err = w.Write(buf[:n]) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // serializeStreamHeader writes an OpenPGP packet header to w where the | ||||
| // length of the packet is unknown. It returns a io.WriteCloser which can be | ||||
| // used to write the contents of the packet. See RFC 4880, section 4.2. | ||||
| func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) { | ||||
| 	err = serializeType(w, ptype) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	out = &partialLengthWriter{w: w} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Packet represents an OpenPGP packet. Users are expected to try casting | ||||
| // instances of this interface to specific packet types. | ||||
| type Packet interface { | ||||
| 	parse(io.Reader) error | ||||
| } | ||||
|  | ||||
| // consumeAll reads from the given Reader until error, returning the number of | ||||
| // bytes read. | ||||
| func consumeAll(r io.Reader) (n int64, err error) { | ||||
| 	var m int | ||||
| 	var buf [1024]byte | ||||
|  | ||||
| 	for { | ||||
| 		m, err = r.Read(buf[:]) | ||||
| 		n += int64(m) | ||||
| 		if err == io.EOF { | ||||
| 			err = nil | ||||
| 			return | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // packetType represents the numeric ids of the different OpenPGP packet types. See | ||||
| // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2 | ||||
| type packetType uint8 | ||||
|  | ||||
| const ( | ||||
| 	packetTypeEncryptedKey              packetType = 1 | ||||
| 	packetTypeSignature                 packetType = 2 | ||||
| 	packetTypeSymmetricKeyEncrypted     packetType = 3 | ||||
| 	packetTypeOnePassSignature          packetType = 4 | ||||
| 	packetTypePrivateKey                packetType = 5 | ||||
| 	packetTypePublicKey                 packetType = 6 | ||||
| 	packetTypePrivateSubkey             packetType = 7 | ||||
| 	packetTypeCompressed                packetType = 8 | ||||
| 	packetTypeSymmetricallyEncrypted    packetType = 9 | ||||
| 	packetTypeLiteralData               packetType = 11 | ||||
| 	packetTypeUserId                    packetType = 13 | ||||
| 	packetTypePublicSubkey              packetType = 14 | ||||
| 	packetTypeUserAttribute             packetType = 17 | ||||
| 	packetTypeSymmetricallyEncryptedMDC packetType = 18 | ||||
| 	packetTypeAEADEncrypted             packetType = 20 | ||||
| ) | ||||
|  | ||||
| // EncryptedDataPacket holds encrypted data. It is currently implemented by | ||||
| // SymmetricallyEncrypted and AEADEncrypted. | ||||
| type EncryptedDataPacket interface { | ||||
| 	Decrypt(CipherFunction, []byte) (io.ReadCloser, error) | ||||
| } | ||||
|  | ||||
| // Read reads a single OpenPGP packet from the given io.Reader. If there is an | ||||
| // error parsing a packet, the whole packet is consumed from the input. | ||||
| func Read(r io.Reader) (p Packet, err error) { | ||||
| 	tag, _, contents, err := readHeader(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch tag { | ||||
| 	case packetTypeEncryptedKey: | ||||
| 		p = new(EncryptedKey) | ||||
| 	case packetTypeSignature: | ||||
| 		p = new(Signature) | ||||
| 	case packetTypeSymmetricKeyEncrypted: | ||||
| 		p = new(SymmetricKeyEncrypted) | ||||
| 	case packetTypeOnePassSignature: | ||||
| 		p = new(OnePassSignature) | ||||
| 	case packetTypePrivateKey, packetTypePrivateSubkey: | ||||
| 		pk := new(PrivateKey) | ||||
| 		if tag == packetTypePrivateSubkey { | ||||
| 			pk.IsSubkey = true | ||||
| 		} | ||||
| 		p = pk | ||||
| 	case packetTypePublicKey, packetTypePublicSubkey: | ||||
| 		isSubkey := tag == packetTypePublicSubkey | ||||
| 		p = &PublicKey{IsSubkey: isSubkey} | ||||
| 	case packetTypeCompressed: | ||||
| 		p = new(Compressed) | ||||
| 	case packetTypeSymmetricallyEncrypted: | ||||
| 		err = errors.UnsupportedError("Symmetrically encrypted packets without MDC are not supported") | ||||
| 	case packetTypeLiteralData: | ||||
| 		p = new(LiteralData) | ||||
| 	case packetTypeUserId: | ||||
| 		p = new(UserId) | ||||
| 	case packetTypeUserAttribute: | ||||
| 		p = new(UserAttribute) | ||||
| 	case packetTypeSymmetricallyEncryptedMDC: | ||||
| 		se := new(SymmetricallyEncrypted) | ||||
| 		se.MDC = true | ||||
| 		p = se | ||||
| 	case packetTypeAEADEncrypted: | ||||
| 		p = new(AEADEncrypted) | ||||
| 	default: | ||||
| 		err = errors.UnknownPacketTypeError(tag) | ||||
| 	} | ||||
| 	if p != nil { | ||||
| 		err = p.parse(contents) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		consumeAll(contents) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // SignatureType represents the different semantic meanings of an OpenPGP | ||||
| // signature. See RFC 4880, section 5.2.1. | ||||
| type SignatureType uint8 | ||||
|  | ||||
| const ( | ||||
| 	SigTypeBinary            SignatureType = 0x00 | ||||
| 	SigTypeText                            = 0x01 | ||||
| 	SigTypeGenericCert                     = 0x10 | ||||
| 	SigTypePersonaCert                     = 0x11 | ||||
| 	SigTypeCasualCert                      = 0x12 | ||||
| 	SigTypePositiveCert                    = 0x13 | ||||
| 	SigTypeSubkeyBinding                   = 0x18 | ||||
| 	SigTypePrimaryKeyBinding               = 0x19 | ||||
| 	SigTypeDirectSignature                 = 0x1F | ||||
| 	SigTypeKeyRevocation                   = 0x20 | ||||
| 	SigTypeSubkeyRevocation                = 0x28 | ||||
| ) | ||||
|  | ||||
| // PublicKeyAlgorithm represents the different public key system specified for | ||||
| // OpenPGP. See | ||||
| // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12 | ||||
| type PublicKeyAlgorithm uint8 | ||||
|  | ||||
| const ( | ||||
| 	PubKeyAlgoRSA     PublicKeyAlgorithm = 1 | ||||
| 	PubKeyAlgoElGamal PublicKeyAlgorithm = 16 | ||||
| 	PubKeyAlgoDSA     PublicKeyAlgorithm = 17 | ||||
| 	// RFC 6637, Section 5. | ||||
| 	PubKeyAlgoECDH  PublicKeyAlgorithm = 18 | ||||
| 	PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | ||||
| 	// https://www.ietf.org/archive/id/draft-koch-eddsa-for-openpgp-04.txt | ||||
| 	PubKeyAlgoEdDSA PublicKeyAlgorithm = 22 | ||||
|  | ||||
| 	// Deprecated in RFC 4880, Section 13.5. Use key flags instead. | ||||
| 	PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 | ||||
| 	PubKeyAlgoRSASignOnly    PublicKeyAlgorithm = 3 | ||||
| ) | ||||
|  | ||||
| // CanEncrypt returns true if it's possible to encrypt a message to a public | ||||
| // key of the given type. | ||||
| func (pka PublicKeyAlgorithm) CanEncrypt() bool { | ||||
| 	switch pka { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH: | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // CanSign returns true if it's possible for a public key of the given type to | ||||
| // sign a message. | ||||
| func (pka PublicKeyAlgorithm) CanSign() bool { | ||||
| 	switch pka { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // CipherFunction represents the different block ciphers specified for OpenPGP. See | ||||
| // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 | ||||
| type CipherFunction algorithm.CipherFunction | ||||
|  | ||||
| const ( | ||||
| 	Cipher3DES   CipherFunction = 2 | ||||
| 	CipherCAST5  CipherFunction = 3 | ||||
| 	CipherAES128 CipherFunction = 7 | ||||
| 	CipherAES192 CipherFunction = 8 | ||||
| 	CipherAES256 CipherFunction = 9 | ||||
| ) | ||||
|  | ||||
| // KeySize returns the key size, in bytes, of cipher. | ||||
| func (cipher CipherFunction) KeySize() int { | ||||
| 	return algorithm.CipherFunction(cipher).KeySize() | ||||
| } | ||||
|  | ||||
| // blockSize returns the block size, in bytes, of cipher. | ||||
| func (cipher CipherFunction) blockSize() int { | ||||
| 	return algorithm.CipherFunction(cipher).BlockSize() | ||||
| } | ||||
|  | ||||
| // new returns a fresh instance of the given cipher. | ||||
| func (cipher CipherFunction) new(key []byte) (block cipher.Block) { | ||||
| 	return algorithm.CipherFunction(cipher).New(key) | ||||
| } | ||||
|  | ||||
| // padToKeySize left-pads a MPI with zeroes to match the length of the | ||||
| // specified RSA public. | ||||
| func padToKeySize(pub *rsa.PublicKey, b []byte) []byte { | ||||
| 	k := (pub.N.BitLen() + 7) / 8 | ||||
| 	if len(b) >= k { | ||||
| 		return b | ||||
| 	} | ||||
| 	bb := make([]byte, k) | ||||
| 	copy(bb[len(bb)-len(b):], b) | ||||
| 	return bb | ||||
| } | ||||
|  | ||||
| // CompressionAlgo Represents the different compression algorithms | ||||
| // supported by OpenPGP (except for BZIP2, which is not currently | ||||
| // supported). See Section 9.3 of RFC 4880. | ||||
| type CompressionAlgo uint8 | ||||
|  | ||||
| const ( | ||||
| 	CompressionNone CompressionAlgo = 0 | ||||
| 	CompressionZIP  CompressionAlgo = 1 | ||||
| 	CompressionZLIB CompressionAlgo = 2 | ||||
| ) | ||||
|  | ||||
| // AEADMode represents the different Authenticated Encryption with Associated | ||||
| // Data specified for OpenPGP. | ||||
| type AEADMode algorithm.AEADMode | ||||
|  | ||||
| const ( | ||||
| 	AEADModeEAX             AEADMode = 1 | ||||
| 	AEADModeOCB             AEADMode = 2 | ||||
| 	AEADModeExperimentalGCM AEADMode = 100 | ||||
| ) | ||||
|  | ||||
| func (mode AEADMode) NonceLength() int { | ||||
| 	return algorithm.AEADMode(mode).NonceLength() | ||||
| } | ||||
|  | ||||
| func (mode AEADMode) TagLength() int { | ||||
| 	return algorithm.AEADMode(mode).TagLength() | ||||
| } | ||||
|  | ||||
| // new returns a fresh instance of the given mode. | ||||
| func (mode AEADMode) new(block cipher.Block) cipher.AEAD { | ||||
| 	return algorithm.AEADMode(mode).New(block) | ||||
| } | ||||
|  | ||||
| // ReasonForRevocation represents a revocation reason code as per RFC4880 | ||||
| // section 5.2.3.23. | ||||
| type ReasonForRevocation uint8 | ||||
|  | ||||
| const ( | ||||
| 	NoReason       ReasonForRevocation = 0 | ||||
| 	KeySuperseded  ReasonForRevocation = 1 | ||||
| 	KeyCompromised ReasonForRevocation = 2 | ||||
| 	KeyRetired     ReasonForRevocation = 3 | ||||
| ) | ||||
							
								
								
									
										780
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										780
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,780 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/sha1" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | ||||
| 	"golang.org/x/crypto/curve25519" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/elgamal" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| ) | ||||
|  | ||||
| // PrivateKey represents a possibly encrypted private key. See RFC 4880, | ||||
| // section 5.5.3. | ||||
| type PrivateKey struct { | ||||
| 	PublicKey | ||||
| 	Encrypted     bool // if true then the private key is unavailable until Decrypt has been called. | ||||
| 	encryptedData []byte | ||||
| 	cipher        CipherFunction | ||||
| 	s2k           func(out, in []byte) | ||||
| 	// An *{rsa|dsa|elgamal|ecdh|ecdsa|ed25519}.PrivateKey or | ||||
| 	// crypto.Signer/crypto.Decrypter (Decryptor RSA only). | ||||
| 	PrivateKey   interface{} | ||||
| 	sha1Checksum bool | ||||
| 	iv           []byte | ||||
|  | ||||
| 	// Type of encryption of the S2K packet | ||||
| 	// Allowed values are 0 (Not encrypted), 254 (SHA1), or | ||||
| 	// 255 (2-byte checksum) | ||||
| 	s2kType S2KType | ||||
| 	// Full parameters of the S2K packet | ||||
| 	s2kParams *s2k.Params | ||||
| } | ||||
|  | ||||
| //S2KType s2k packet type | ||||
| type S2KType uint8 | ||||
|  | ||||
| const ( | ||||
| 	// S2KNON unencrypt | ||||
| 	S2KNON S2KType = 0 | ||||
| 	// S2KSHA1 sha1 sum check | ||||
| 	S2KSHA1 S2KType = 254 | ||||
| 	// S2KCHECKSUM sum check | ||||
| 	S2KCHECKSUM S2KType = 255 | ||||
| ) | ||||
|  | ||||
| func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewEdDSAPrivateKey(creationTime time.Time, priv *ed25519.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pub := priv.Public().(ed25519.PublicKey) | ||||
| 	pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pub) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewECDHPrivateKey(creationTime time.Time, priv *ecdh.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| // NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that | ||||
| // implements RSA, ECDSA or EdDSA. | ||||
| func NewSignerPrivateKey(creationTime time.Time, signer crypto.Signer) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	// In general, the public Keys should be used as pointers. We still | ||||
| 	// type-switch on the values, for backwards-compatibility. | ||||
| 	switch pubkey := signer.Public().(type) { | ||||
| 	case *rsa.PublicKey: | ||||
| 		pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey) | ||||
| 	case rsa.PublicKey: | ||||
| 		pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey) | ||||
| 	case *ecdsa.PublicKey: | ||||
| 		pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey) | ||||
| 	case ecdsa.PublicKey: | ||||
| 		pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey) | ||||
| 	case *ed25519.PublicKey: | ||||
| 		pk.PublicKey = *NewEdDSAPublicKey(creationTime, pubkey) | ||||
| 	case ed25519.PublicKey: | ||||
| 		pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey) | ||||
| 	default: | ||||
| 		panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") | ||||
| 	} | ||||
| 	pk.PrivateKey = signer | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| // NewDecrypterPrivateKey creates a PrivateKey from a *{rsa|elgamal|ecdh}.PrivateKey. | ||||
| func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	switch priv := decrypter.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey) | ||||
| 	case *elgamal.PrivateKey: | ||||
| 		pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey) | ||||
| 	case *ecdh.PrivateKey: | ||||
| 		pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey) | ||||
| 	default: | ||||
| 		panic("openpgp: unknown decrypter type in NewDecrypterPrivateKey") | ||||
| 	} | ||||
| 	pk.PrivateKey = decrypter | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parse(r io.Reader) (err error) { | ||||
| 	err = (&pk.PublicKey).parse(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	v5 := pk.PublicKey.Version == 5 | ||||
|  | ||||
| 	var buf [1]byte | ||||
| 	_, err = readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.s2kType = S2KType(buf[0]) | ||||
| 	var optCount [1]byte | ||||
| 	if v5 { | ||||
| 		if _, err = readFull(r, optCount[:]); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch pk.s2kType { | ||||
| 	case S2KNON: | ||||
| 		pk.s2k = nil | ||||
| 		pk.Encrypted = false | ||||
| 	case S2KSHA1, S2KCHECKSUM: | ||||
| 		if v5 && pk.s2kType == S2KCHECKSUM { | ||||
| 			return errors.StructuralError("wrong s2k identifier for version 5") | ||||
| 		} | ||||
| 		_, err = readFull(r, buf[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.cipher = CipherFunction(buf[0]) | ||||
| 		pk.s2kParams, err = s2k.ParseIntoParams(r) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if pk.s2kParams.Dummy() { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.s2k, err = pk.s2kParams.Function() | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.Encrypted = true | ||||
| 		if pk.s2kType == S2KSHA1 { | ||||
| 			pk.sha1Checksum = true | ||||
| 		} | ||||
| 	default: | ||||
| 		return errors.UnsupportedError("deprecated s2k function in private key") | ||||
| 	} | ||||
|  | ||||
| 	if pk.Encrypted { | ||||
| 		blockSize := pk.cipher.blockSize() | ||||
| 		if blockSize == 0 { | ||||
| 			return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher))) | ||||
| 		} | ||||
| 		pk.iv = make([]byte, blockSize) | ||||
| 		_, err = readFull(r, pk.iv) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var privateKeyData []byte | ||||
| 	if v5 { | ||||
| 		var n [4]byte /* secret material four octet count */ | ||||
| 		_, err = readFull(r, n[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		count := uint32(uint32(n[0])<<24 | uint32(n[1])<<16 | uint32(n[2])<<8 | uint32(n[3])) | ||||
| 		if !pk.Encrypted { | ||||
| 			count = count + 2 /* two octet checksum */ | ||||
| 		} | ||||
| 		privateKeyData = make([]byte, count) | ||||
| 		_, err = readFull(r, privateKeyData) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} else { | ||||
| 		privateKeyData, err = ioutil.ReadAll(r) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if !pk.Encrypted { | ||||
| 		return pk.parsePrivateKey(privateKeyData) | ||||
| 	} | ||||
|  | ||||
| 	pk.encryptedData = privateKeyData | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Dummy returns true if the private key is a dummy key. This is a GNU extension. | ||||
| func (pk *PrivateKey) Dummy() bool { | ||||
| 	return pk.s2kParams.Dummy() | ||||
| } | ||||
|  | ||||
| func mod64kHash(d []byte) uint16 { | ||||
| 	var h uint16 | ||||
| 	for _, b := range d { | ||||
| 		h += uint16(b) | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) Serialize(w io.Writer) (err error) { | ||||
| 	contents := bytes.NewBuffer(nil) | ||||
| 	err = pk.PublicKey.serializeWithoutHeaders(contents) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if _, err = contents.Write([]byte{uint8(pk.s2kType)}); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	optional := bytes.NewBuffer(nil) | ||||
| 	if pk.Encrypted || pk.Dummy() { | ||||
| 		optional.Write([]byte{uint8(pk.cipher)}) | ||||
| 		if err := pk.s2kParams.Serialize(optional); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if pk.Encrypted { | ||||
| 			optional.Write(pk.iv) | ||||
| 		} | ||||
| 	} | ||||
| 	if pk.Version == 5 { | ||||
| 		contents.Write([]byte{uint8(optional.Len())}) | ||||
| 	} | ||||
| 	io.Copy(contents, optional) | ||||
|  | ||||
| 	if !pk.Dummy() { | ||||
| 		l := 0 | ||||
| 		var priv []byte | ||||
| 		if !pk.Encrypted { | ||||
| 			buf := bytes.NewBuffer(nil) | ||||
| 			err = pk.serializePrivateKey(buf) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			l = buf.Len() | ||||
| 			if pk.sha1Checksum { | ||||
| 				h := sha1.New() | ||||
| 				h.Write(buf.Bytes()) | ||||
| 				buf.Write(h.Sum(nil)) | ||||
| 			} else { | ||||
| 				checksum := mod64kHash(buf.Bytes()) | ||||
| 				buf.Write([]byte{byte(checksum >> 8), byte(checksum)}) | ||||
| 			} | ||||
| 			priv = buf.Bytes() | ||||
| 		} else { | ||||
| 			priv, l = pk.encryptedData, len(pk.encryptedData) | ||||
| 		} | ||||
|  | ||||
| 		if pk.Version == 5 { | ||||
| 			contents.Write([]byte{byte(l >> 24), byte(l >> 16), byte(l >> 8), byte(l)}) | ||||
| 		} | ||||
| 		contents.Write(priv) | ||||
| 	} | ||||
|  | ||||
| 	ptype := packetTypePrivateKey | ||||
| 	if pk.IsSubkey { | ||||
| 		ptype = packetTypePrivateSubkey | ||||
| 	} | ||||
| 	err = serializeHeader(w, ptype, contents.Len()) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = io.Copy(w, contents) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error { | ||||
| 	if _, err := w.Write(new(encoding.MPI).SetBig(priv.D).EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write(new(encoding.MPI).SetBig(priv.Primes[1]).EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := w.Write(new(encoding.MPI).SetBig(priv.Primes[0]).EncodedBytes()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.Precomputed.Qinv).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error { | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.X).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error { | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.X).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error { | ||||
| 	_, err := w.Write(new(encoding.MPI).SetBig(priv.D).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeEdDSAPrivateKey(w io.Writer, priv *ed25519.PrivateKey) error { | ||||
| 	keySize := ed25519.PrivateKeySize - ed25519.PublicKeySize | ||||
| 	_, err := w.Write(encoding.NewMPI((*priv)[:keySize]).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error { | ||||
| 	_, err := w.Write(encoding.NewMPI(priv.D).EncodedBytes()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Decrypt decrypts an encrypted private key using a passphrase. | ||||
| func (pk *PrivateKey) Decrypt(passphrase []byte) error { | ||||
| 	if pk.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	if !pk.Encrypted { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	key := make([]byte, pk.cipher.KeySize()) | ||||
| 	pk.s2k(key, passphrase) | ||||
| 	block := pk.cipher.new(key) | ||||
| 	cfb := cipher.NewCFBDecrypter(block, pk.iv) | ||||
|  | ||||
| 	data := make([]byte, len(pk.encryptedData)) | ||||
| 	cfb.XORKeyStream(data, pk.encryptedData) | ||||
|  | ||||
| 	if pk.sha1Checksum { | ||||
| 		if len(data) < sha1.Size { | ||||
| 			return errors.StructuralError("truncated private key data") | ||||
| 		} | ||||
| 		h := sha1.New() | ||||
| 		h.Write(data[:len(data)-sha1.Size]) | ||||
| 		sum := h.Sum(nil) | ||||
| 		if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { | ||||
| 			return errors.StructuralError("private key checksum failure") | ||||
| 		} | ||||
| 		data = data[:len(data)-sha1.Size] | ||||
| 	} else { | ||||
| 		if len(data) < 2 { | ||||
| 			return errors.StructuralError("truncated private key data") | ||||
| 		} | ||||
| 		var sum uint16 | ||||
| 		for i := 0; i < len(data)-2; i++ { | ||||
| 			sum += uint16(data[i]) | ||||
| 		} | ||||
| 		if data[len(data)-2] != uint8(sum>>8) || | ||||
| 			data[len(data)-1] != uint8(sum) { | ||||
| 			return errors.StructuralError("private key checksum failure") | ||||
| 		} | ||||
| 		data = data[:len(data)-2] | ||||
| 	} | ||||
|  | ||||
| 	err := pk.parsePrivateKey(data) | ||||
| 	if _, ok := err.(errors.KeyInvalidError); ok { | ||||
| 		return errors.KeyInvalidError("invalid key parameters") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Mark key as unencrypted | ||||
| 	pk.s2kType = S2KNON | ||||
| 	pk.s2k = nil | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Encrypt encrypts an unencrypted private key using a passphrase. | ||||
| func (pk *PrivateKey) Encrypt(passphrase []byte) error { | ||||
| 	priv := bytes.NewBuffer(nil) | ||||
| 	err := pk.serializePrivateKey(priv) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	//Default config of private key encryption | ||||
| 	pk.cipher = CipherAES256 | ||||
| 	s2kConfig := &s2k.Config{ | ||||
| 		S2KMode:  3, //Iterated | ||||
| 		S2KCount: 65536, | ||||
| 		Hash:     crypto.SHA256, | ||||
| 	} | ||||
|  | ||||
| 	pk.s2kParams, err = s2k.Generate(rand.Reader, s2kConfig) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	privateKeyBytes := priv.Bytes() | ||||
| 	key := make([]byte, pk.cipher.KeySize()) | ||||
|  | ||||
| 	pk.sha1Checksum = true | ||||
| 	pk.s2k, err = pk.s2kParams.Function() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.s2k(key, passphrase) | ||||
| 	block := pk.cipher.new(key) | ||||
| 	pk.iv = make([]byte, pk.cipher.blockSize()) | ||||
| 	_, err = rand.Read(pk.iv) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	cfb := cipher.NewCFBEncrypter(block, pk.iv) | ||||
|  | ||||
| 	if pk.sha1Checksum { | ||||
| 		pk.s2kType = S2KSHA1 | ||||
| 		h := sha1.New() | ||||
| 		h.Write(privateKeyBytes) | ||||
| 		sum := h.Sum(nil) | ||||
| 		privateKeyBytes = append(privateKeyBytes, sum...) | ||||
| 	} else { | ||||
| 		pk.s2kType = S2KCHECKSUM | ||||
| 		var sum uint16 | ||||
| 		for _, b := range privateKeyBytes { | ||||
| 			sum += uint16(b) | ||||
| 		} | ||||
| 		priv.Write([]byte{uint8(sum >> 8), uint8(sum)}) | ||||
| 	} | ||||
|  | ||||
| 	pk.encryptedData = make([]byte, len(privateKeyBytes)) | ||||
| 	cfb.XORKeyStream(pk.encryptedData, privateKeyBytes) | ||||
| 	pk.Encrypted = true | ||||
| 	pk.PrivateKey = nil | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) { | ||||
| 	switch priv := pk.PrivateKey.(type) { | ||||
| 	case *rsa.PrivateKey: | ||||
| 		err = serializeRSAPrivateKey(w, priv) | ||||
| 	case *dsa.PrivateKey: | ||||
| 		err = serializeDSAPrivateKey(w, priv) | ||||
| 	case *elgamal.PrivateKey: | ||||
| 		err = serializeElGamalPrivateKey(w, priv) | ||||
| 	case *ecdsa.PrivateKey: | ||||
| 		err = serializeECDSAPrivateKey(w, priv) | ||||
| 	case *ed25519.PrivateKey: | ||||
| 		err = serializeEdDSAPrivateKey(w, priv) | ||||
| 	case *ecdh.PrivateKey: | ||||
| 		err = serializeECDHPrivateKey(w, priv) | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("unknown private key type") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) { | ||||
| 	switch pk.PublicKey.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly: | ||||
| 		return pk.parseRSAPrivateKey(data) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		return pk.parseDSAPrivateKey(data) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		return pk.parseElGamalPrivateKey(data) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		return pk.parseECDSAPrivateKey(data) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		return pk.parseECDHPrivateKey(data) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		return pk.parseEdDSAPrivateKey(data) | ||||
| 	} | ||||
| 	panic("impossible") | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { | ||||
| 	rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey) | ||||
| 	rsaPriv := new(rsa.PrivateKey) | ||||
| 	rsaPriv.PublicKey = *rsaPub | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	p := new(encoding.MPI) | ||||
| 	if _, err := p.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	q := new(encoding.MPI) | ||||
| 	if _, err := q.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	rsaPriv.D = new(big.Int).SetBytes(d.Bytes()) | ||||
| 	rsaPriv.Primes = make([]*big.Int, 2) | ||||
| 	rsaPriv.Primes[0] = new(big.Int).SetBytes(p.Bytes()) | ||||
| 	rsaPriv.Primes[1] = new(big.Int).SetBytes(q.Bytes()) | ||||
| 	if err := rsaPriv.Validate(); err != nil { | ||||
| 		return errors.KeyInvalidError(err.Error()) | ||||
| 	} | ||||
| 	rsaPriv.Precompute() | ||||
| 	pk.PrivateKey = rsaPriv | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) { | ||||
| 	dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey) | ||||
| 	dsaPriv := new(dsa.PrivateKey) | ||||
| 	dsaPriv.PublicKey = *dsaPub | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	x := new(encoding.MPI) | ||||
| 	if _, err := x.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	dsaPriv.X = new(big.Int).SetBytes(x.Bytes()) | ||||
| 	if err := validateDSAParameters(dsaPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = dsaPriv | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) { | ||||
| 	pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey) | ||||
| 	priv := new(elgamal.PrivateKey) | ||||
| 	priv.PublicKey = *pub | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	x := new(encoding.MPI) | ||||
| 	if _, err := x.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	priv.X = new(big.Int).SetBytes(x.Bytes()) | ||||
| 	if err := validateElGamalParameters(priv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = priv | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { | ||||
| 	ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey) | ||||
| 	ecdsaPriv := new(ecdsa.PrivateKey) | ||||
| 	ecdsaPriv.PublicKey = *ecdsaPub | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	ecdsaPriv.D = new(big.Int).SetBytes(d.Bytes()) | ||||
| 	if err := validateECDSAParameters(ecdsaPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = ecdsaPriv | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) { | ||||
| 	ecdhPub := pk.PublicKey.PublicKey.(*ecdh.PublicKey) | ||||
| 	ecdhPriv := new(ecdh.PrivateKey) | ||||
| 	ecdhPriv.PublicKey = *ecdhPub | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	ecdhPriv.D = d.Bytes() | ||||
| 	if err := validateECDHParameters(ecdhPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = ecdhPriv | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) { | ||||
| 	eddsaPub := pk.PublicKey.PublicKey.(*ed25519.PublicKey) | ||||
| 	eddsaPriv := make(ed25519.PrivateKey, ed25519.PrivateKeySize) | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d := new(encoding.MPI) | ||||
| 	if _, err := d.ReadFrom(buf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	priv := d.Bytes() | ||||
| 	copy(eddsaPriv[32-len(priv):32], priv) | ||||
| 	copy(eddsaPriv[32:], (*eddsaPub)[:]) | ||||
| 	if err := validateEdDSAParameters(&eddsaPriv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pk.PrivateKey = &eddsaPriv | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func validateECDSAParameters(priv *ecdsa.PrivateKey) error { | ||||
| 	return validateCommonECC(priv.Curve, priv.D.Bytes(), priv.X, priv.Y) | ||||
| } | ||||
|  | ||||
| func validateECDHParameters(priv *ecdh.PrivateKey) error { | ||||
| 	if priv.CurveType != ecc.Curve25519 { | ||||
| 		return validateCommonECC(priv.Curve, priv.D, priv.X, priv.Y) | ||||
| 	} | ||||
| 	// Handle Curve25519 | ||||
| 	Q := priv.X.Bytes()[1:] | ||||
| 	var d [32]byte | ||||
| 	// Copy reversed d | ||||
| 	l := len(priv.D) | ||||
| 	for i := 0; i < l; i++ { | ||||
| 		d[i] = priv.D[l-i-1] | ||||
| 	} | ||||
| 	var expectedQ [32]byte | ||||
| 	curve25519.ScalarBaseMult(&expectedQ, &d) | ||||
| 	if !bytes.Equal(Q, expectedQ[:]) { | ||||
| 		return errors.KeyInvalidError("ECDH curve25519: invalid point") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func validateCommonECC(curve elliptic.Curve, d []byte, X, Y *big.Int) error { | ||||
| 	// the public point should not be at infinity (0,0) | ||||
| 	zero := new(big.Int) | ||||
| 	if X.Cmp(zero) == 0 && Y.Cmp(zero) == 0 { | ||||
| 		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): infinity point", curve.Params().Name)) | ||||
| 	} | ||||
| 	// re-derive the public point Q' = (X,Y) = dG | ||||
| 	// to compare to declared Q in public key | ||||
| 	expectedX, expectedY := curve.ScalarBaseMult(d) | ||||
| 	if X.Cmp(expectedX) != 0 || Y.Cmp(expectedY) != 0 { | ||||
| 		return errors.KeyInvalidError(fmt.Sprintf("ecc (%s): invalid point", curve.Params().Name)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func validateEdDSAParameters(priv *ed25519.PrivateKey) error { | ||||
| 	// In EdDSA, the serialized public point is stored as part of private key (together with the seed), | ||||
| 	// hence we can re-derive the key from the seed | ||||
| 	seed := priv.Seed() | ||||
| 	expectedPriv := ed25519.NewKeyFromSeed(seed) | ||||
| 	if !bytes.Equal(*priv, expectedPriv) { | ||||
| 		return errors.KeyInvalidError("eddsa: invalid point") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func validateDSAParameters(priv *dsa.PrivateKey) error { | ||||
| 	p := priv.P // group prime | ||||
| 	q := priv.Q // subgroup order | ||||
| 	g := priv.G // g has order q mod p | ||||
| 	x := priv.X // secret | ||||
| 	y := priv.Y // y == g**x mod p | ||||
| 	one := big.NewInt(1) | ||||
| 	// expect g, y >= 2 and g < p | ||||
| 	if g.Cmp(one) <= 0 || y.Cmp(one) <= 0 || g.Cmp(p) > 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid group") | ||||
| 	} | ||||
| 	// expect p > q | ||||
| 	if p.Cmp(q) <= 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid group prime") | ||||
| 	} | ||||
| 	// q should be large enough and divide p-1 | ||||
| 	pSub1 := new(big.Int).Sub(p, one) | ||||
| 	if q.BitLen() < 150 || new(big.Int).Mod(pSub1, q).Cmp(big.NewInt(0)) != 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid order") | ||||
| 	} | ||||
| 	// confirm that g has order q mod p | ||||
| 	if !q.ProbablyPrime(32) || new(big.Int).Exp(g, q, p).Cmp(one) != 0 { | ||||
| 		return errors.KeyInvalidError("dsa: invalid order") | ||||
| 	} | ||||
| 	// check y | ||||
| 	if new(big.Int).Exp(g, x, p).Cmp(y) != 0 { | ||||
| 		return errors.KeyInvalidError("dsa: mismatching values") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func validateElGamalParameters(priv *elgamal.PrivateKey) error { | ||||
| 	p := priv.P // group prime | ||||
| 	g := priv.G // g has order p-1 mod p | ||||
| 	x := priv.X // secret | ||||
| 	y := priv.Y // y == g**x mod p | ||||
| 	one := big.NewInt(1) | ||||
| 	// Expect g, y >= 2 and g < p | ||||
| 	if g.Cmp(one) <= 0 || y.Cmp(one) <= 0 || g.Cmp(p) > 0 { | ||||
| 		return errors.KeyInvalidError("elgamal: invalid group") | ||||
| 	} | ||||
| 	if p.BitLen() < 1024 { | ||||
| 		return errors.KeyInvalidError("elgamal: group order too small") | ||||
| 	} | ||||
| 	pSub1 := new(big.Int).Sub(p, one) | ||||
| 	if new(big.Int).Exp(g, pSub1, p).Cmp(one) != 0 { | ||||
| 		return errors.KeyInvalidError("elgamal: invalid group") | ||||
| 	} | ||||
| 	// Since p-1 is not prime, g might have a smaller order that divides p-1. | ||||
| 	// We cannot confirm the exact order of g, but we make sure it is not too small. | ||||
| 	gExpI := new(big.Int).Set(g) | ||||
| 	i := 1 | ||||
| 	threshold := 2 << 17 // we want order > threshold | ||||
| 	for i < threshold { | ||||
| 		i++ // we check every order to make sure key validation is not easily bypassed by guessing y' | ||||
| 		gExpI.Mod(new(big.Int).Mul(gExpI, g), p) | ||||
| 		if gExpI.Cmp(one) == 0 { | ||||
| 			return errors.KeyInvalidError("elgamal: order too small") | ||||
| 		} | ||||
| 	} | ||||
| 	// Check y | ||||
| 	if new(big.Int).Exp(g, x, p).Cmp(y) != 0 { | ||||
| 		return errors.KeyInvalidError("elgamal: mismatching values") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										12
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| package packet | ||||
|  | ||||
| // Generated with `gpg --export-secret-keys "Test Key 2"` | ||||
| const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec" | ||||
|  | ||||
| // Generated by `gpg --export-secret-keys` followed by a manual extraction of | ||||
| // the ElGamal subkey from the packets. | ||||
| const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc" | ||||
|  | ||||
| // pkcs1PrivKeyHex is a PKCS#1, RSA private key. | ||||
| // Generated by `openssl genrsa 1024 | openssl rsa -outform DER  | xxd -p` | ||||
| const pkcs1PrivKeyHex = "3082025d02010002818100e98edfa1c3b35884a54d0b36a6a603b0290fa85e49e30fa23fc94fef9c6790bc4849928607aa48d809da326fb42a969d06ad756b98b9c1a90f5d4a2b6d0ac05953c97f4da3120164a21a679793ce181c906dc01d235cc085ddcdf6ea06c389b6ab8885dfd685959e693138856a68a7e5db263337ff82a088d583a897cf2d59e9020301000102818100b6d5c9eb70b02d5369b3ee5b520a14490b5bde8a317d36f7e4c74b7460141311d1e5067735f8f01d6f5908b2b96fbd881f7a1ab9a84d82753e39e19e2d36856be960d05ac9ef8e8782ea1b6d65aee28fdfe1d61451e8cff0adfe84322f12cf455028b581cf60eb9e0e140ba5d21aeba6c2634d7c65318b9a665fc01c3191ca21024100fa5e818da3705b0fa33278bb28d4b6f6050388af2d4b75ec9375dd91ccf2e7d7068086a8b82a8f6282e4fbbdb8a7f2622eb97295249d87acea7f5f816f54d347024100eecf9406d7dc49cdfb95ab1eff4064de84c7a30f64b2798936a0d2018ba9eb52e4b636f82e96c49cc63b80b675e91e40d1b2e4017d4b9adaf33ab3d9cf1c214f024100c173704ace742c082323066226a4655226819a85304c542b9dacbeacbf5d1881ee863485fcf6f59f3a604f9b42289282067447f2b13dfeed3eab7851fc81e0550240741fc41f3fc002b382eed8730e33c5d8de40256e4accee846667f536832f711ab1d4590e7db91a8a116ac5bff3be13d3f9243ff2e976662aa9b395d907f8e9c9024046a5696c9ef882363e06c9fa4e2f5b580906452befba03f4a99d0f873697ef1f851d2226ca7934b30b7c3e80cb634a67172bbbf4781735fe3e09263e2dd723e7" | ||||
							
								
								
									
										825
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										825
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,825 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/sha1" | ||||
| 	"crypto/sha256" | ||||
| 	_ "crypto/sha512" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/elgamal" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/ecc" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| ) | ||||
|  | ||||
| type kdfHashFunction byte | ||||
| type kdfAlgorithm byte | ||||
|  | ||||
| // PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2. | ||||
| type PublicKey struct { | ||||
| 	Version      int | ||||
| 	CreationTime time.Time | ||||
| 	PubKeyAlgo   PublicKeyAlgorithm | ||||
| 	PublicKey    interface{} // *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey or *eddsa.PublicKey | ||||
| 	Fingerprint  []byte | ||||
| 	KeyId        uint64 | ||||
| 	IsSubkey     bool | ||||
|  | ||||
| 	// RFC 4880 fields | ||||
| 	n, e, p, q, g, y encoding.Field | ||||
|  | ||||
| 	// RFC 6637 fields | ||||
| 	// oid contains the OID byte sequence identifying the elliptic curve used | ||||
| 	oid encoding.Field | ||||
|  | ||||
| 	// kdf stores key derivation function parameters | ||||
| 	// used for ECDH encryption. See RFC 6637, Section 9. | ||||
| 	kdf encoding.Field | ||||
| } | ||||
|  | ||||
| // UpgradeToV5 updates the version of the key to v5, and updates all necessary | ||||
| // fields. | ||||
| func (pk *PublicKey) UpgradeToV5() { | ||||
| 	pk.Version = 5 | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| } | ||||
|  | ||||
| // signingKey provides a convenient abstraction over signature verification | ||||
| // for v3 and v4 public keys. | ||||
| type signingKey interface { | ||||
| 	SerializeForHash(io.Writer) error | ||||
| 	SerializeSignaturePrefix(io.Writer) | ||||
| 	serializeWithoutHeaders(io.Writer) error | ||||
| } | ||||
|  | ||||
| // NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. | ||||
| func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoRSA, | ||||
| 		PublicKey:    pub, | ||||
| 		n:            new(encoding.MPI).SetBig(pub.N), | ||||
| 		e:            new(encoding.MPI).SetBig(big.NewInt(int64(pub.E))), | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| // NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey. | ||||
| func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            new(encoding.MPI).SetBig(pub.P), | ||||
| 		q:            new(encoding.MPI).SetBig(pub.Q), | ||||
| 		g:            new(encoding.MPI).SetBig(pub.G), | ||||
| 		y:            new(encoding.MPI).SetBig(pub.Y), | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| // NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey. | ||||
| func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoElGamal, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            new(encoding.MPI).SetBig(pub.P), | ||||
| 		g:            new(encoding.MPI).SetBig(pub.G), | ||||
| 		y:            new(encoding.MPI).SetBig(pub.Y), | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoECDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            encoding.NewMPI(elliptic.Marshal(pub.Curve, pub.X, pub.Y)), | ||||
| 	} | ||||
|  | ||||
| 	curveInfo := ecc.FindByCurve(pub.Curve) | ||||
| 	if curveInfo == nil { | ||||
| 		panic("unknown elliptic curve") | ||||
| 	} | ||||
| 	pk.oid = curveInfo.Oid | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewECDHPublicKey(creationTime time.Time, pub *ecdh.PublicKey) *PublicKey { | ||||
| 	var pk *PublicKey | ||||
| 	var curveInfo *ecc.CurveInfo | ||||
| 	var kdf = encoding.NewOID([]byte{0x1, pub.Hash.Id(), pub.Cipher.Id()}) | ||||
| 	if pub.CurveType == ecc.Curve25519 { | ||||
| 		pk = &PublicKey{ | ||||
| 			Version:      4, | ||||
| 			CreationTime: creationTime, | ||||
| 			PubKeyAlgo:   PubKeyAlgoECDH, | ||||
| 			PublicKey:    pub, | ||||
| 			p:            encoding.NewMPI(pub.X.Bytes()), | ||||
| 			kdf:          kdf, | ||||
| 		} | ||||
| 		curveInfo = ecc.FindByName("Curve25519") | ||||
| 	} else { | ||||
| 		pk = &PublicKey{ | ||||
| 			Version:      4, | ||||
| 			CreationTime: creationTime, | ||||
| 			PubKeyAlgo:   PubKeyAlgoECDH, | ||||
| 			PublicKey:    pub, | ||||
| 			p:            encoding.NewMPI(elliptic.Marshal(pub.Curve, pub.X, pub.Y)), | ||||
| 			kdf:          kdf, | ||||
| 		} | ||||
| 		curveInfo = ecc.FindByCurve(pub.Curve) | ||||
| 	} | ||||
| 	if curveInfo == nil { | ||||
| 		panic("unknown elliptic curve") | ||||
| 	} | ||||
| 	pk.oid = curveInfo.Oid | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewEdDSAPublicKey(creationTime time.Time, pub *ed25519.PublicKey) *PublicKey { | ||||
| 	curveInfo := ecc.FindByName("Ed25519") | ||||
| 	pk := &PublicKey{ | ||||
| 		Version:      4, | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoEdDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		oid:          curveInfo.Oid, | ||||
| 		// Native point format, see draft-koch-eddsa-for-openpgp-04, Appendix B | ||||
| 		p: encoding.NewMPI(append([]byte{0x40}, *pub...)), | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func (pk *PublicKey) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.5.2 | ||||
| 	var buf [6]byte | ||||
| 	_, err = readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] != 4 && buf[0] != 5 { | ||||
| 		return errors.UnsupportedError("public key version " + strconv.Itoa(int(buf[0]))) | ||||
| 	} | ||||
|  | ||||
| 	pk.Version = int(buf[0]) | ||||
| 	if pk.Version == 5 { | ||||
| 		var n [4]byte | ||||
| 		_, err = readFull(r, n[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) | ||||
| 	pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5]) | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		err = pk.parseRSA(r) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		err = pk.parseDSA(r) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		err = pk.parseElGamal(r) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		err = pk.parseECDSA(r) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		err = pk.parseECDH(r) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		err = pk.parseEdDSA(r) | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerprintAndKeyId() | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (pk *PublicKey) setFingerprintAndKeyId() { | ||||
| 	// RFC 4880, section 12.2 | ||||
| 	if pk.Version == 5 { | ||||
| 		fingerprint := sha256.New() | ||||
| 		pk.SerializeForHash(fingerprint) | ||||
| 		pk.Fingerprint = make([]byte, 32) | ||||
| 		copy(pk.Fingerprint, fingerprint.Sum(nil)) | ||||
| 		pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[:8]) | ||||
| 	} else { | ||||
| 		fingerprint := sha1.New() | ||||
| 		pk.SerializeForHash(fingerprint) | ||||
| 		pk.Fingerprint = make([]byte, 20) | ||||
| 		copy(pk.Fingerprint, fingerprint.Sum(nil)) | ||||
| 		pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20]) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // parseRSA parses RSA public key material from the given Reader. See RFC 4880, | ||||
| // section 5.5.2. | ||||
| func (pk *PublicKey) parseRSA(r io.Reader) (err error) { | ||||
| 	pk.n = new(encoding.MPI) | ||||
| 	if _, err = pk.n.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.e = new(encoding.MPI) | ||||
| 	if _, err = pk.e.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if len(pk.e.Bytes()) > 3 { | ||||
| 		err = errors.UnsupportedError("large public exponent") | ||||
| 		return | ||||
| 	} | ||||
| 	rsa := &rsa.PublicKey{ | ||||
| 		N: new(big.Int).SetBytes(pk.n.Bytes()), | ||||
| 		E: 0, | ||||
| 	} | ||||
| 	for i := 0; i < len(pk.e.Bytes()); i++ { | ||||
| 		rsa.E <<= 8 | ||||
| 		rsa.E |= int(pk.e.Bytes()[i]) | ||||
| 	} | ||||
| 	pk.PublicKey = rsa | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // parseDSA parses DSA public key material from the given Reader. See RFC 4880, | ||||
| // section 5.5.2. | ||||
| func (pk *PublicKey) parseDSA(r io.Reader) (err error) { | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.q = new(encoding.MPI) | ||||
| 	if _, err = pk.q.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.g = new(encoding.MPI) | ||||
| 	if _, err = pk.g.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.y = new(encoding.MPI) | ||||
| 	if _, err = pk.y.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	dsa := new(dsa.PublicKey) | ||||
| 	dsa.P = new(big.Int).SetBytes(pk.p.Bytes()) | ||||
| 	dsa.Q = new(big.Int).SetBytes(pk.q.Bytes()) | ||||
| 	dsa.G = new(big.Int).SetBytes(pk.g.Bytes()) | ||||
| 	dsa.Y = new(big.Int).SetBytes(pk.y.Bytes()) | ||||
| 	pk.PublicKey = dsa | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // parseElGamal parses ElGamal public key material from the given Reader. See | ||||
| // RFC 4880, section 5.5.2. | ||||
| func (pk *PublicKey) parseElGamal(r io.Reader) (err error) { | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.g = new(encoding.MPI) | ||||
| 	if _, err = pk.g.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.y = new(encoding.MPI) | ||||
| 	if _, err = pk.y.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	elgamal := new(elgamal.PublicKey) | ||||
| 	elgamal.P = new(big.Int).SetBytes(pk.p.Bytes()) | ||||
| 	elgamal.G = new(big.Int).SetBytes(pk.g.Bytes()) | ||||
| 	elgamal.Y = new(big.Int).SetBytes(pk.y.Bytes()) | ||||
| 	pk.PublicKey = elgamal | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // parseECDSA parses ECDSA public key material from the given Reader. See | ||||
| // RFC 6637, Section 9. | ||||
| func (pk *PublicKey) parseECDSA(r io.Reader) (err error) { | ||||
| 	pk.oid = new(encoding.OID) | ||||
| 	if _, err = pk.oid.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var c elliptic.Curve | ||||
| 	curveInfo := ecc.FindByOid(pk.oid) | ||||
| 	if curveInfo == nil || curveInfo.SigAlgorithm != ecc.ECDSA { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid)) | ||||
| 	} | ||||
| 	c = curveInfo.Curve | ||||
| 	x, y := elliptic.Unmarshal(c, pk.p.Bytes()) | ||||
| 	if x == nil { | ||||
| 		return errors.UnsupportedError("failed to parse EC point") | ||||
| 	} | ||||
| 	pk.PublicKey = &ecdsa.PublicKey{Curve: c, X: x, Y: y} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // parseECDH parses ECDH public key material from the given Reader. See | ||||
| // RFC 6637, Section 9. | ||||
| func (pk *PublicKey) parseECDH(r io.Reader) (err error) { | ||||
| 	pk.oid = new(encoding.OID) | ||||
| 	if _, err = pk.oid.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.kdf = new(encoding.OID) | ||||
| 	if _, err = pk.kdf.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	curveInfo := ecc.FindByOid(pk.oid) | ||||
| 	if curveInfo == nil { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid)) | ||||
| 	} | ||||
|  | ||||
| 	c := curveInfo.Curve | ||||
| 	cType := curveInfo.CurveType | ||||
|  | ||||
| 	var x, y *big.Int | ||||
| 	if cType == ecc.Curve25519 { | ||||
| 		x = new(big.Int) | ||||
| 		x.SetBytes(pk.p.Bytes()) | ||||
| 	} else { | ||||
| 		x, y = elliptic.Unmarshal(c, pk.p.Bytes()) | ||||
| 	} | ||||
| 	if x == nil { | ||||
| 		return errors.UnsupportedError("failed to parse EC point") | ||||
| 	} | ||||
|  | ||||
| 	if kdfLen := len(pk.kdf.Bytes()); kdfLen < 3 { | ||||
| 		return errors.UnsupportedError("unsupported ECDH KDF length: " + strconv.Itoa(kdfLen)) | ||||
| 	} | ||||
| 	if reserved := pk.kdf.Bytes()[0]; reserved != 0x01 { | ||||
| 		return errors.UnsupportedError("unsupported KDF reserved field: " + strconv.Itoa(int(reserved))) | ||||
| 	} | ||||
| 	kdfHash, ok := algorithm.HashById[pk.kdf.Bytes()[1]] | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("unsupported ECDH KDF hash: " + strconv.Itoa(int(pk.kdf.Bytes()[1]))) | ||||
| 	} | ||||
| 	kdfCipher, ok := algorithm.CipherById[pk.kdf.Bytes()[2]] | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("unsupported ECDH KDF cipher: " + strconv.Itoa(int(pk.kdf.Bytes()[2]))) | ||||
| 	} | ||||
|  | ||||
| 	pk.PublicKey = &ecdh.PublicKey{ | ||||
| 		CurveType: cType, | ||||
| 		Curve:     c, | ||||
| 		X:         x, | ||||
| 		Y:         y, | ||||
| 		KDF: ecdh.KDF{ | ||||
| 			Hash:   kdfHash, | ||||
| 			Cipher: kdfCipher, | ||||
| 		}, | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (pk *PublicKey) parseEdDSA(r io.Reader) (err error) { | ||||
| 	pk.oid = new(encoding.OID) | ||||
| 	if _, err = pk.oid.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	curveInfo := ecc.FindByOid(pk.oid) | ||||
| 	if curveInfo == nil || curveInfo.SigAlgorithm != ecc.EdDSA { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid)) | ||||
| 	} | ||||
| 	pk.p = new(encoding.MPI) | ||||
| 	if _, err = pk.p.ReadFrom(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	eddsa := make(ed25519.PublicKey, ed25519.PublicKeySize) | ||||
| 	switch flag := pk.p.Bytes()[0]; flag { | ||||
| 	case 0x04: | ||||
| 		// TODO: see _grcy_ecc_eddsa_ensure_compact in grcypt | ||||
| 		return errors.UnsupportedError("unsupported EdDSA compression: " + strconv.Itoa(int(flag))) | ||||
| 	case 0x40: | ||||
| 		copy(eddsa[:], pk.p.Bytes()[1:]) | ||||
| 	default: | ||||
| 		return errors.UnsupportedError("unsupported EdDSA compression: " + strconv.Itoa(int(flag))) | ||||
| 	} | ||||
|  | ||||
| 	pk.PublicKey = &eddsa | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // SerializeForHash serializes the PublicKey to w with the special packet | ||||
| // header format needed for hashing. | ||||
| func (pk *PublicKey) SerializeForHash(w io.Writer) error { | ||||
| 	pk.SerializeSignaturePrefix(w) | ||||
| 	return pk.serializeWithoutHeaders(w) | ||||
| } | ||||
|  | ||||
| // SerializeSignaturePrefix writes the prefix for this public key to the given Writer. | ||||
| // The prefix is used when calculating a signature over this public key. See | ||||
| // RFC 4880, section 5.2.4. | ||||
| func (pk *PublicKey) SerializeSignaturePrefix(w io.Writer) { | ||||
| 	var pLength = pk.algorithmSpecificByteCount() | ||||
| 	if pk.Version == 5 { | ||||
| 		pLength += 10 // version, timestamp (4), algorithm, key octet count (4). | ||||
| 		w.Write([]byte{ | ||||
| 			0x9A, | ||||
| 			byte(pLength >> 24), | ||||
| 			byte(pLength >> 16), | ||||
| 			byte(pLength >> 8), | ||||
| 			byte(pLength), | ||||
| 		}) | ||||
| 		return | ||||
| 	} | ||||
| 	pLength += 6 | ||||
| 	w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) | ||||
| } | ||||
|  | ||||
| func (pk *PublicKey) Serialize(w io.Writer) (err error) { | ||||
| 	length := 6 // 6 byte header | ||||
| 	length += pk.algorithmSpecificByteCount() | ||||
| 	if pk.Version == 5 { | ||||
| 		length += 4 // octet key count | ||||
| 	} | ||||
| 	packetType := packetTypePublicKey | ||||
| 	if pk.IsSubkey { | ||||
| 		packetType = packetTypePublicSubkey | ||||
| 	} | ||||
| 	err = serializeHeader(w, packetType, length) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return pk.serializeWithoutHeaders(w) | ||||
| } | ||||
|  | ||||
| func (pk *PublicKey) algorithmSpecificByteCount() int { | ||||
| 	length := 0 | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		length += int(pk.n.EncodedLength()) | ||||
| 		length += int(pk.e.EncodedLength()) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 		length += int(pk.q.EncodedLength()) | ||||
| 		length += int(pk.g.EncodedLength()) | ||||
| 		length += int(pk.y.EncodedLength()) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 		length += int(pk.g.EncodedLength()) | ||||
| 		length += int(pk.y.EncodedLength()) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		length += int(pk.oid.EncodedLength()) | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		length += int(pk.oid.EncodedLength()) | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 		length += int(pk.kdf.EncodedLength()) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		length += int(pk.oid.EncodedLength()) | ||||
| 		length += int(pk.p.EncodedLength()) | ||||
| 	default: | ||||
| 		panic("unknown public key algorithm") | ||||
| 	} | ||||
| 	return length | ||||
| } | ||||
|  | ||||
| // serializeWithoutHeaders marshals the PublicKey to w in the form of an | ||||
| // OpenPGP public key packet, not including the packet header. | ||||
| func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { | ||||
| 	t := uint32(pk.CreationTime.Unix()) | ||||
| 	if _, err = w.Write([]byte{ | ||||
| 		byte(pk.Version), | ||||
| 		byte(t >> 24), byte(t >> 16), byte(t >> 8), byte(t), | ||||
| 		byte(pk.PubKeyAlgo), | ||||
| 	}); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if pk.Version == 5 { | ||||
| 		n := pk.algorithmSpecificByteCount() | ||||
| 		if _, err = w.Write([]byte{ | ||||
| 			byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n), | ||||
| 		}); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		if _, err = w.Write(pk.n.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.e.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		if _, err = w.Write(pk.p.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.q.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.g.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.y.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		if _, err = w.Write(pk.p.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.g.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.y.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		if _, err = w.Write(pk.oid.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.p.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		if _, err = w.Write(pk.oid.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(pk.p.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.kdf.EncodedBytes()) | ||||
| 		return | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		if _, err = w.Write(pk.oid.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(pk.p.EncodedBytes()) | ||||
| 		return | ||||
| 	} | ||||
| 	return errors.InvalidArgumentError("bad public-key algorithm") | ||||
| } | ||||
|  | ||||
| // CanSign returns true iff this public key can generate signatures | ||||
| func (pk *PublicKey) CanSign() bool { | ||||
| 	return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal && pk.PubKeyAlgo != PubKeyAlgoECDH | ||||
| } | ||||
|  | ||||
| // VerifySignature returns nil iff sig is a valid signature, made by this | ||||
| // public key, of the data hashed into signed. signed is mutated by this call. | ||||
| func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) { | ||||
| 	if !pk.CanSign() { | ||||
| 		return errors.InvalidArgumentError("public key cannot generate signatures") | ||||
| 	} | ||||
| 	if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) { | ||||
| 		sig.AddMetadataToHashSuffix() | ||||
| 	} | ||||
| 	signed.Write(sig.HashSuffix) | ||||
| 	hashBytes := signed.Sum(nil) | ||||
| 	if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { | ||||
| 		return errors.SignatureError("hash tag doesn't match") | ||||
| 	} | ||||
|  | ||||
| 	if pk.PubKeyAlgo != sig.PubKeyAlgo { | ||||
| 		return errors.InvalidArgumentError("public key and signature use different algorithms") | ||||
| 	} | ||||
|  | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) | ||||
| 		err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.Bytes())) | ||||
| 		if err != nil { | ||||
| 			return errors.SignatureError("RSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey) | ||||
| 		// Need to truncate hashBytes to match FIPS 186-3 section 4.6. | ||||
| 		subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 | ||||
| 		if len(hashBytes) > subgroupSize { | ||||
| 			hashBytes = hashBytes[:subgroupSize] | ||||
| 		} | ||||
| 		if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.Bytes()), new(big.Int).SetBytes(sig.DSASigS.Bytes())) { | ||||
| 			return errors.SignatureError("DSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) | ||||
| 		if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.Bytes()), new(big.Int).SetBytes(sig.ECDSASigS.Bytes())) { | ||||
| 			return errors.SignatureError("ECDSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		eddsaPublicKey := pk.PublicKey.(*ed25519.PublicKey) | ||||
|  | ||||
| 		sigR := sig.EdDSASigR.Bytes() | ||||
| 		sigS := sig.EdDSASigS.Bytes() | ||||
|  | ||||
| 		eddsaSig := make([]byte, ed25519.SignatureSize) | ||||
| 		copy(eddsaSig[32-len(sigR):32], sigR) | ||||
| 		copy(eddsaSig[64-len(sigS):], sigS) | ||||
|  | ||||
| 		if !ed25519.Verify(*eddsaPublicKey, hashBytes, eddsaSig) { | ||||
| 			return errors.SignatureError("EdDSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	default: | ||||
| 		return errors.SignatureError("Unsupported public key algorithm used in signature") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // keySignatureHash returns a Hash of the message that needs to be signed for | ||||
| // pk to assert a subkey relationship to signed. | ||||
| func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { | ||||
| 	if !hashFunc.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash function") | ||||
| 	} | ||||
| 	h = hashFunc.New() | ||||
|  | ||||
| 	// RFC 4880, section 5.2.4 | ||||
| 	err = pk.SerializeForHash(h) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err = signed.SerializeForHash(h) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // VerifyKeySignature returns nil iff sig is a valid signature, made by this | ||||
| // public key, of signed. | ||||
| func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error { | ||||
| 	h, err := keySignatureHash(pk, signed, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = pk.VerifySignature(h, sig); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if sig.FlagSign { | ||||
| 		// Signing subkeys must be cross-signed. See | ||||
| 		// https://www.gnupg.org/faq/subkey-cross-certify.html. | ||||
| 		if sig.EmbeddedSignature == nil { | ||||
| 			return errors.StructuralError("signing subkey is missing cross-signature") | ||||
| 		} | ||||
| 		// Verify the cross-signature. This is calculated over the same | ||||
| 		// data as the main signature, so we cannot just recursively | ||||
| 		// call signed.VerifyKeySignature(...) | ||||
| 		if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil { | ||||
| 			return errors.StructuralError("error while hashing for cross-signature: " + err.Error()) | ||||
| 		} | ||||
| 		if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil { | ||||
| 			return errors.StructuralError("error while verifying cross-signature: " + err.Error()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { | ||||
| 	if !hashFunc.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash function") | ||||
| 	} | ||||
| 	h = hashFunc.New() | ||||
|  | ||||
| 	// RFC 4880, section 5.2.4 | ||||
| 	err = pk.SerializeForHash(h) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // VerifyRevocationSignature returns nil iff sig is a valid signature, made by this | ||||
| // public key. | ||||
| func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) { | ||||
| 	h, err := keyRevocationHash(pk, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignature(h, sig) | ||||
| } | ||||
|  | ||||
| // VerifySubkeyRevocationSignature returns nil iff sig is a valid subkey revocation signature, | ||||
| // made by the passed in signingKey. | ||||
| func (pk *PublicKey) VerifySubkeyRevocationSignature(sig *Signature, signingKey *PublicKey) (err error) { | ||||
| 	h, err := keyRevocationHash(pk, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return signingKey.VerifySignature(h, sig) | ||||
| } | ||||
|  | ||||
| // userIdSignatureHash returns a Hash of the message that needs to be signed | ||||
| // to assert that pk is a valid key for id. | ||||
| func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) { | ||||
| 	if !hashFunc.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash function") | ||||
| 	} | ||||
| 	h = hashFunc.New() | ||||
|  | ||||
| 	// RFC 4880, section 5.2.4 | ||||
| 	pk.SerializeSignaturePrefix(h) | ||||
| 	pk.serializeWithoutHeaders(h) | ||||
|  | ||||
| 	var buf [5]byte | ||||
| 	buf[0] = 0xb4 | ||||
| 	buf[1] = byte(len(id) >> 24) | ||||
| 	buf[2] = byte(len(id) >> 16) | ||||
| 	buf[3] = byte(len(id) >> 8) | ||||
| 	buf[4] = byte(len(id)) | ||||
| 	h.Write(buf[:]) | ||||
| 	h.Write([]byte(id)) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // VerifyUserIdSignature returns nil iff sig is a valid signature, made by this | ||||
| // public key, that id is the identity of pub. | ||||
| func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) { | ||||
| 	h, err := userIdSignatureHash(id, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignature(h, sig) | ||||
| } | ||||
|  | ||||
| // KeyIdString returns the public key's fingerprint in capital hex | ||||
| // (e.g. "6C7EE1B8621CC013"). | ||||
| func (pk *PublicKey) KeyIdString() string { | ||||
| 	return fmt.Sprintf("%X", pk.Fingerprint[12:20]) | ||||
| } | ||||
|  | ||||
| // KeyIdShortString returns the short form of public key's fingerprint | ||||
| // in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). | ||||
| func (pk *PublicKey) KeyIdShortString() string { | ||||
| 	return fmt.Sprintf("%X", pk.Fingerprint[16:20]) | ||||
| } | ||||
|  | ||||
| // BitLength returns the bit length for the given public key. | ||||
| func (pk *PublicKey) BitLength() (bitLength uint16, err error) { | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		bitLength = pk.n.BitLength() | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		bitLength = pk.p.BitLength() | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("bad public-key algorithm") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // KeyExpired returns whether sig is a self-signature of a key that has | ||||
| // expired or is created in the future. | ||||
| func (pk *PublicKey) KeyExpired(sig *Signature, currentTime time.Time) bool { | ||||
| 	if pk.CreationTime.After(currentTime) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if sig.KeyLifetimeSecs == nil || *sig.KeyLifetimeSecs == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	expiry := pk.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) | ||||
| 	return currentTime.After(expiry) | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key_test_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| package packet | ||||
|  | ||||
| const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb" | ||||
|  | ||||
| const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001" | ||||
|  | ||||
| const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed" | ||||
|  | ||||
| const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0" | ||||
|  | ||||
| const ecdsaFingerprintHex = "9892270b38b8980b05c8d56d43fe956c542ca00b" | ||||
|  | ||||
| const ecdsaPkDataHex = "9893045071c29413052b8104002304230401f4867769cedfa52c325018896245443968e52e51d0c2df8d939949cb5b330f2921711fbee1c9b9dddb95d15cb0255e99badeddda7cc23d9ddcaacbc290969b9f24019375d61c2e4e3b36953a28d8b2bc95f78c3f1d592fb24499be348656a7b17e3963187b4361afe497bc5f9f81213f04069f8e1fb9e6a6290ae295ca1a92b894396cb4" | ||||
|  | ||||
| const ecdhFingerprintHex = "722354df2475a42164d1d49faa8b938f9a201946" | ||||
|  | ||||
| const ecdhPkDataHex = "b90073044d53059212052b810400220303042faa84024a20b6735c4897efa5bfb41bf85b7eefeab5ca0cb9ffc8ea04a46acb25534a577694f9e25340a4ab5223a9dd1eda530c8aa2e6718db10d7e672558c7736fe09369ea5739a2a3554bf16d41faa50562f11c6d39bbd5dffb6b9a9ec91803010909" | ||||
|  | ||||
| const eddsaFingerprintHex = "b2d5e5ec0e6deca6bc8eeeb00907e75e1dd99ad8" | ||||
|  | ||||
| const eddsaPkDataHex = "98330456e2132b16092b06010401da470f01010740bbda39266affa511a8c2d02edf690fb784b0499c4406185811a163539ef11dc1b41d74657374696e67203c74657374696e674074657374696e672e636f6d3e8879041316080021050256e2132b021b03050b09080702061508090a0b020416020301021e01021780000a09100907e75e1dd99ad86d0c00fe39d2008359352782bc9b61ac382584cd8eff3f57a18c2287e3afeeb05d1f04ba00fe2d0bc1ddf3ff8adb9afa3e7d9287244b4ec567f3db4d60b74a9b5465ed528203" | ||||
|  | ||||
| // Source: https://sites.google.com/site/brainhub/pgpecckeys#TOC-ECC-NIST-P-384-key | ||||
| const ecc384PubHex = `99006f044d53059213052b81040022030304f6b8c5aced5b84ef9f4a209db2e4a9dfb70d28cb8c10ecd57674a9fa5a67389942b62d5e51367df4c7bfd3f8e500feecf07ed265a621a8ebbbe53e947ec78c677eba143bd1533c2b350e1c29f82313e1e1108eba063be1e64b10e6950e799c2db42465635f6473615f64685f333834203c6f70656e70677040627261696e6875622e6f72673e8900cb04101309005305024d530592301480000000002000077072656665727265642d656d61696c2d656e636f64696e67407067702e636f6d7067706d696d65040b090807021901051b03000000021602051e010000000415090a08000a0910098033880f54719fca2b0180aa37350968bd5f115afd8ce7bc7b103822152dbff06d0afcda835329510905b98cb469ba208faab87c7412b799e7b633017f58364ea480e8a1a3f253a0c5f22c446e8be9a9fce6210136ee30811abbd49139de28b5bdf8dc36d06ae748579e9ff503b90073044d53059212052b810400220303042faa84024a20b6735c4897efa5bfb41bf85b7eefeab5ca0cb9ffc8ea04a46acb25534a577694f9e25340a4ab5223a9dd1eda530c8aa2e6718db10d7e672558c7736fe09369ea5739a2a3554bf16d41faa50562f11c6d39bbd5dffb6b9a9ec9180301090989008404181309000c05024d530592051b0c000000000a0910098033880f54719f80970180eee7a6d8fcee41ee4f9289df17f9bcf9d955dca25c583b94336f3a2b2d4986dc5cf417b8d2dc86f741a9e1a6d236c0e3017d1c76575458a0cfb93ae8a2b274fcc65ceecd7a91eec83656ba13219969f06945b48c56bd04152c3a0553c5f2f4bd1267` | ||||
							
								
								
									
										78
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| ) | ||||
|  | ||||
| // Reader reads packets from an io.Reader and allows packets to be 'unread' so | ||||
| // that they result from the next call to Next. | ||||
| type Reader struct { | ||||
| 	q       []Packet | ||||
| 	readers []io.Reader | ||||
| } | ||||
|  | ||||
| // New io.Readers are pushed when a compressed or encrypted packet is processed | ||||
| // and recursively treated as a new source of packets. However, a carefully | ||||
| // crafted packet can trigger an infinite recursive sequence of packets. See | ||||
| // http://mumble.net/~campbell/misc/pgp-quine | ||||
| // https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402 | ||||
| // This constant limits the number of recursive packets that may be pushed. | ||||
| const maxReaders = 32 | ||||
|  | ||||
| // Next returns the most recently unread Packet, or reads another packet from | ||||
| // the top-most io.Reader. Unknown packet types are skipped. | ||||
| func (r *Reader) Next() (p Packet, err error) { | ||||
| 	if len(r.q) > 0 { | ||||
| 		p = r.q[len(r.q)-1] | ||||
| 		r.q = r.q[:len(r.q)-1] | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	for len(r.readers) > 0 { | ||||
| 		p, err = Read(r.readers[len(r.readers)-1]) | ||||
| 		if err == nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if err == io.EOF { | ||||
| 			r.readers = r.readers[:len(r.readers)-1] | ||||
| 			continue | ||||
| 		} | ||||
| 		// TODO: Add strict mode that rejects unknown packets, instead of ignoring them. | ||||
| 		if _, ok := err.(errors.UnknownPacketTypeError); !ok { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil, io.EOF | ||||
| } | ||||
|  | ||||
| // Push causes the Reader to start reading from a new io.Reader. When an EOF | ||||
| // error is seen from the new io.Reader, it is popped and the Reader continues | ||||
| // to read from the next most recent io.Reader. Push returns a StructuralError | ||||
| // if pushing the reader would exceed the maximum recursion level, otherwise it | ||||
| // returns nil. | ||||
| func (r *Reader) Push(reader io.Reader) (err error) { | ||||
| 	if len(r.readers) >= maxReaders { | ||||
| 		return errors.StructuralError("too many layers of packets") | ||||
| 	} | ||||
| 	r.readers = append(r.readers, reader) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Unread causes the given Packet to be returned from the next call to Next. | ||||
| func (r *Reader) Unread(p Packet) { | ||||
| 	r.q = append(r.q, p) | ||||
| } | ||||
|  | ||||
| func NewReader(r io.Reader) *Reader { | ||||
| 	return &Reader{ | ||||
| 		q:       nil, | ||||
| 		readers: []io.Reader{r}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										983
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										983
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,983 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto" | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"encoding/asn1" | ||||
| 	"encoding/binary" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/internal/encoding" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// See RFC 4880, section 5.2.3.21 for details. | ||||
| 	KeyFlagCertify = 1 << iota | ||||
| 	KeyFlagSign | ||||
| 	KeyFlagEncryptCommunications | ||||
| 	KeyFlagEncryptStorage | ||||
| ) | ||||
|  | ||||
| // Signature represents a signature. See RFC 4880, section 5.2. | ||||
| type Signature struct { | ||||
| 	Version    int | ||||
| 	SigType    SignatureType | ||||
| 	PubKeyAlgo PublicKeyAlgorithm | ||||
| 	Hash       crypto.Hash | ||||
|  | ||||
| 	// HashSuffix is extra data that is hashed in after the signed data. | ||||
| 	HashSuffix []byte | ||||
| 	// HashTag contains the first two bytes of the hash for fast rejection | ||||
| 	// of bad signed data. | ||||
| 	HashTag [2]byte | ||||
|  | ||||
| 	// Metadata includes format, filename and time, and is protected by v5 | ||||
| 	// signatures of type 0x00 or 0x01. This metadata is included into the hash | ||||
| 	// computation; if nil, six 0x00 bytes are used instead. See section 5.2.4. | ||||
| 	Metadata *LiteralData | ||||
|  | ||||
| 	CreationTime time.Time | ||||
|  | ||||
| 	RSASignature         encoding.Field | ||||
| 	DSASigR, DSASigS     encoding.Field | ||||
| 	ECDSASigR, ECDSASigS encoding.Field | ||||
| 	EdDSASigR, EdDSASigS encoding.Field | ||||
|  | ||||
| 	// rawSubpackets contains the unparsed subpackets, in order. | ||||
| 	rawSubpackets []outputSubpacket | ||||
|  | ||||
| 	// The following are optional so are nil when not included in the | ||||
| 	// signature. | ||||
|  | ||||
| 	SigLifetimeSecs, KeyLifetimeSecs                        *uint32 | ||||
| 	PreferredSymmetric, PreferredHash, PreferredCompression []uint8 | ||||
| 	PreferredAEAD                                           []uint8 | ||||
| 	IssuerKeyId                                             *uint64 | ||||
| 	IssuerFingerprint                                       []byte | ||||
| 	IsPrimaryId                                             *bool | ||||
|  | ||||
| 	// PolicyURI can be set to the URI of a document that describes the | ||||
| 	// policy under which the signature was issued. See RFC 4880, section | ||||
| 	// 5.2.3.20 for details. | ||||
| 	PolicyURI string | ||||
|  | ||||
| 	// FlagsValid is set if any flags were given. See RFC 4880, section | ||||
| 	// 5.2.3.21 for details. | ||||
| 	FlagsValid                                                           bool | ||||
| 	FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool | ||||
|  | ||||
| 	// RevocationReason is set if this signature has been revoked. | ||||
| 	// See RFC 4880, section 5.2.3.23 for details. | ||||
| 	RevocationReason     *uint8 | ||||
| 	RevocationReasonText string | ||||
|  | ||||
| 	// In a self-signature, these flags are set there is a features subpacket | ||||
| 	// indicating that the issuer implementation supports these features | ||||
| 	// (section 5.2.5.25). | ||||
| 	MDC, AEAD, V5Keys bool | ||||
|  | ||||
| 	// EmbeddedSignature, if non-nil, is a signature of the parent key, by | ||||
| 	// this key. This prevents an attacker from claiming another's signing | ||||
| 	// subkey as their own. | ||||
| 	EmbeddedSignature *Signature | ||||
|  | ||||
| 	outSubpackets []outputSubpacket | ||||
| } | ||||
|  | ||||
| func (sig *Signature) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.2.3 | ||||
| 	var buf [5]byte | ||||
| 	_, err = readFull(r, buf[:1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] != 4 && buf[0] != 5 { | ||||
| 		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | ||||
| 		return | ||||
| 	} | ||||
| 	sig.Version = int(buf[0]) | ||||
| 	_, err = readFull(r, buf[:5]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sig.SigType = SignatureType(buf[0]) | ||||
| 	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var ok bool | ||||
| 	sig.Hash, ok = s2k.HashIdToHash(buf[2]) | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) | ||||
| 	} | ||||
|  | ||||
| 	hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) | ||||
| 	hashedSubpackets := make([]byte, hashedSubpacketsLength) | ||||
| 	_, err = readFull(r, hashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sig.buildHashSuffix(hashedSubpackets) | ||||
| 	err = parseSignatureSubpackets(sig, hashedSubpackets, true) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, err = readFull(r, buf[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1]) | ||||
| 	unhashedSubpackets := make([]byte, unhashedSubpacketsLength) | ||||
| 	_, err = readFull(r, unhashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = parseSignatureSubpackets(sig, unhashedSubpackets, false) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, err = readFull(r, sig.HashTag[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		sig.RSASignature = new(encoding.MPI) | ||||
| 		_, err = sig.RSASignature.ReadFrom(r) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		sig.DSASigR = new(encoding.MPI) | ||||
| 		if _, err = sig.DSASigR.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		sig.DSASigS = new(encoding.MPI) | ||||
| 		_, err = sig.DSASigS.ReadFrom(r) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		sig.ECDSASigR = new(encoding.MPI) | ||||
| 		if _, err = sig.ECDSASigR.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		sig.ECDSASigS = new(encoding.MPI) | ||||
| 		_, err = sig.ECDSASigS.ReadFrom(r) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sig.EdDSASigR = new(encoding.MPI) | ||||
| 		if _, err = sig.EdDSASigR.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		sig.EdDSASigS = new(encoding.MPI) | ||||
| 		if _, err = sig.EdDSASigS.ReadFrom(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	default: | ||||
| 		panic("unreachable") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // parseSignatureSubpackets parses subpackets of the main signature packet. See | ||||
| // RFC 4880, section 5.2.3.1. | ||||
| func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { | ||||
| 	for len(subpackets) > 0 { | ||||
| 		subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if sig.CreationTime.IsZero() { | ||||
| 		err = errors.StructuralError("no creation time in signature") | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| type signatureSubpacketType uint8 | ||||
|  | ||||
| const ( | ||||
| 	creationTimeSubpacket        signatureSubpacketType = 2 | ||||
| 	signatureExpirationSubpacket signatureSubpacketType = 3 | ||||
| 	keyExpirationSubpacket       signatureSubpacketType = 9 | ||||
| 	prefSymmetricAlgosSubpacket  signatureSubpacketType = 11 | ||||
| 	issuerSubpacket              signatureSubpacketType = 16 | ||||
| 	prefHashAlgosSubpacket       signatureSubpacketType = 21 | ||||
| 	prefCompressionSubpacket     signatureSubpacketType = 22 | ||||
| 	primaryUserIdSubpacket       signatureSubpacketType = 25 | ||||
| 	policyUriSubpacket           signatureSubpacketType = 26 | ||||
| 	keyFlagsSubpacket            signatureSubpacketType = 27 | ||||
| 	reasonForRevocationSubpacket signatureSubpacketType = 29 | ||||
| 	featuresSubpacket            signatureSubpacketType = 30 | ||||
| 	embeddedSignatureSubpacket   signatureSubpacketType = 32 | ||||
| 	issuerFingerprintSubpacket   signatureSubpacketType = 33 | ||||
| 	prefAeadAlgosSubpacket       signatureSubpacketType = 34 | ||||
| ) | ||||
|  | ||||
| // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. | ||||
| func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { | ||||
| 	// RFC 4880, section 5.2.3.1 | ||||
| 	var ( | ||||
| 		length     uint32 | ||||
| 		packetType signatureSubpacketType | ||||
| 		isCritical bool | ||||
| 	) | ||||
| 	switch { | ||||
| 	case subpacket[0] < 192: | ||||
| 		length = uint32(subpacket[0]) | ||||
| 		subpacket = subpacket[1:] | ||||
| 	case subpacket[0] < 255: | ||||
| 		if len(subpacket) < 2 { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 | ||||
| 		subpacket = subpacket[2:] | ||||
| 	default: | ||||
| 		if len(subpacket) < 5 { | ||||
| 			goto Truncated | ||||
| 		} | ||||
| 		length = uint32(subpacket[1])<<24 | | ||||
| 			uint32(subpacket[2])<<16 | | ||||
| 			uint32(subpacket[3])<<8 | | ||||
| 			uint32(subpacket[4]) | ||||
| 		subpacket = subpacket[5:] | ||||
| 	} | ||||
| 	if length > uint32(len(subpacket)) { | ||||
| 		goto Truncated | ||||
| 	} | ||||
| 	rest = subpacket[length:] | ||||
| 	subpacket = subpacket[:length] | ||||
| 	if len(subpacket) == 0 { | ||||
| 		err = errors.StructuralError("zero length signature subpacket") | ||||
| 		return | ||||
| 	} | ||||
| 	packetType = signatureSubpacketType(subpacket[0] & 0x7f) | ||||
| 	isCritical = subpacket[0]&0x80 == 0x80 | ||||
| 	subpacket = subpacket[1:] | ||||
| 	sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) | ||||
| 	switch packetType { | ||||
| 	case creationTimeSubpacket: | ||||
| 		if !isHashed { | ||||
| 			err = errors.StructuralError("signature creation time in non-hashed area") | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 4 { | ||||
| 			err = errors.StructuralError("signature creation time not four bytes") | ||||
| 			return | ||||
| 		} | ||||
| 		t := binary.BigEndian.Uint32(subpacket) | ||||
| 		sig.CreationTime = time.Unix(int64(t), 0) | ||||
| 	case signatureExpirationSubpacket: | ||||
| 		// Signature expiration time, section 5.2.3.10 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 4 { | ||||
| 			err = errors.StructuralError("expiration subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.SigLifetimeSecs = new(uint32) | ||||
| 		*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) | ||||
| 	case keyExpirationSubpacket: | ||||
| 		// Key expiration time, section 5.2.3.6 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 4 { | ||||
| 			err = errors.StructuralError("key expiration subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.KeyLifetimeSecs = new(uint32) | ||||
| 		*sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) | ||||
| 	case prefSymmetricAlgosSubpacket: | ||||
| 		// Preferred symmetric algorithms, section 5.2.3.7 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredSymmetric = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredSymmetric, subpacket) | ||||
| 	case issuerSubpacket: | ||||
| 		if sig.Version > 4 { | ||||
| 			err = errors.StructuralError("issuer subpacket found in v5 key") | ||||
| 		} | ||||
| 		// Issuer, section 5.2.3.5 | ||||
| 		if len(subpacket) != 8 { | ||||
| 			err = errors.StructuralError("issuer subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.IssuerKeyId = new(uint64) | ||||
| 		*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) | ||||
| 	case prefHashAlgosSubpacket: | ||||
| 		// Preferred hash algorithms, section 5.2.3.8 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredHash = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredHash, subpacket) | ||||
| 	case prefCompressionSubpacket: | ||||
| 		// Preferred compression algorithms, section 5.2.3.9 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredCompression = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredCompression, subpacket) | ||||
| 	case primaryUserIdSubpacket: | ||||
| 		// Primary User ID, section 5.2.3.19 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) != 1 { | ||||
| 			err = errors.StructuralError("primary user id subpacket with bad length") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.IsPrimaryId = new(bool) | ||||
| 		if subpacket[0] > 0 { | ||||
| 			*sig.IsPrimaryId = true | ||||
| 		} | ||||
| 	case keyFlagsSubpacket: | ||||
| 		// Key flags, section 5.2.3.21 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) == 0 { | ||||
| 			err = errors.StructuralError("empty key flags subpacket") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.FlagsValid = true | ||||
| 		if subpacket[0]&KeyFlagCertify != 0 { | ||||
| 			sig.FlagCertify = true | ||||
| 		} | ||||
| 		if subpacket[0]&KeyFlagSign != 0 { | ||||
| 			sig.FlagSign = true | ||||
| 		} | ||||
| 		if subpacket[0]&KeyFlagEncryptCommunications != 0 { | ||||
| 			sig.FlagEncryptCommunications = true | ||||
| 		} | ||||
| 		if subpacket[0]&KeyFlagEncryptStorage != 0 { | ||||
| 			sig.FlagEncryptStorage = true | ||||
| 		} | ||||
| 	case reasonForRevocationSubpacket: | ||||
| 		// Reason For Revocation, section 5.2.3.23 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) == 0 { | ||||
| 			err = errors.StructuralError("empty revocation reason subpacket") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.RevocationReason = new(uint8) | ||||
| 		*sig.RevocationReason = subpacket[0] | ||||
| 		sig.RevocationReasonText = string(subpacket[1:]) | ||||
| 	case featuresSubpacket: | ||||
| 		// Features subpacket, section 5.2.3.24 specifies a very general | ||||
| 		// mechanism for OpenPGP implementations to signal support for new | ||||
| 		// features. | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		if len(subpacket) > 0 { | ||||
| 			if subpacket[0]&0x01 != 0 { | ||||
| 				sig.MDC = true | ||||
| 			} | ||||
| 			if subpacket[0]&0x02 != 0 { | ||||
| 				sig.AEAD = true | ||||
| 			} | ||||
| 			if subpacket[0]&0x04 != 0 { | ||||
| 				sig.V5Keys = true | ||||
| 			} | ||||
| 		} | ||||
| 	case embeddedSignatureSubpacket: | ||||
| 		// Only usage is in signatures that cross-certify | ||||
| 		// signing subkeys. section 5.2.3.26 describes the | ||||
| 		// format, with its usage described in section 11.1 | ||||
| 		if sig.EmbeddedSignature != nil { | ||||
| 			err = errors.StructuralError("Cannot have multiple embedded signatures") | ||||
| 			return | ||||
| 		} | ||||
| 		sig.EmbeddedSignature = new(Signature) | ||||
| 		// Embedded signatures are required to be v4 signatures see | ||||
| 		// section 12.1. However, we only parse v4 signatures in this | ||||
| 		// file anyway. | ||||
| 		if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { | ||||
| 			return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) | ||||
| 		} | ||||
| 	case policyUriSubpacket: | ||||
| 		// Policy URI, section 5.2.3.20 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PolicyURI = string(subpacket) | ||||
| 	case issuerFingerprintSubpacket: | ||||
| 		v, l := subpacket[0], len(subpacket[1:]) | ||||
| 		if v == 5 && l != 32 || v != 5 && l != 20 { | ||||
| 			return nil, errors.StructuralError("bad fingerprint length") | ||||
| 		} | ||||
| 		sig.IssuerFingerprint = make([]byte, l) | ||||
| 		copy(sig.IssuerFingerprint, subpacket[1:]) | ||||
| 		sig.IssuerKeyId = new(uint64) | ||||
| 		if v == 5 { | ||||
| 			*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket[1:9]) | ||||
| 		} else { | ||||
| 			*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket[13:21]) | ||||
| 		} | ||||
| 	case prefAeadAlgosSubpacket: | ||||
| 		// Preferred symmetric algorithms, section 5.2.3.8 | ||||
| 		if !isHashed { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.PreferredAEAD = make([]byte, len(subpacket)) | ||||
| 		copy(sig.PreferredAEAD, subpacket) | ||||
| 	default: | ||||
| 		if isCritical { | ||||
| 			err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
|  | ||||
| Truncated: | ||||
| 	err = errors.StructuralError("signature subpacket truncated") | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // subpacketLengthLength returns the length, in bytes, of an encoded length value. | ||||
| func subpacketLengthLength(length int) int { | ||||
| 	if length < 192 { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	if length < 16320 { | ||||
| 		return 2 | ||||
| 	} | ||||
| 	return 5 | ||||
| } | ||||
|  | ||||
| func (sig *Signature) CheckKeyIdOrFingerprint(pk *PublicKey) bool { | ||||
| 	if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) >= 20 { | ||||
| 		return bytes.Equal(sig.IssuerFingerprint, pk.Fingerprint) | ||||
| 	} | ||||
| 	return sig.IssuerKeyId != nil && *sig.IssuerKeyId == pk.KeyId | ||||
| } | ||||
|  | ||||
| // serializeSubpacketLength marshals the given length into to. | ||||
| func serializeSubpacketLength(to []byte, length int) int { | ||||
| 	// RFC 4880, Section 4.2.2. | ||||
| 	if length < 192 { | ||||
| 		to[0] = byte(length) | ||||
| 		return 1 | ||||
| 	} | ||||
| 	if length < 16320 { | ||||
| 		length -= 192 | ||||
| 		to[0] = byte((length >> 8) + 192) | ||||
| 		to[1] = byte(length) | ||||
| 		return 2 | ||||
| 	} | ||||
| 	to[0] = 255 | ||||
| 	to[1] = byte(length >> 24) | ||||
| 	to[2] = byte(length >> 16) | ||||
| 	to[3] = byte(length >> 8) | ||||
| 	to[4] = byte(length) | ||||
| 	return 5 | ||||
| } | ||||
|  | ||||
| // subpacketsLength returns the serialized length, in bytes, of the given | ||||
| // subpackets. | ||||
| func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) { | ||||
| 	for _, subpacket := range subpackets { | ||||
| 		if subpacket.hashed == hashed { | ||||
| 			length += subpacketLengthLength(len(subpacket.contents) + 1) | ||||
| 			length += 1 // type byte | ||||
| 			length += len(subpacket.contents) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // serializeSubpackets marshals the given subpackets into to. | ||||
| func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { | ||||
| 	for _, subpacket := range subpackets { | ||||
| 		if subpacket.hashed == hashed { | ||||
| 			n := serializeSubpacketLength(to, len(subpacket.contents)+1) | ||||
| 			to[n] = byte(subpacket.subpacketType) | ||||
| 			if subpacket.isCritical { | ||||
| 				to[n] |= 0x80 | ||||
| 			} | ||||
| 			to = to[1+n:] | ||||
| 			n = copy(to, subpacket.contents) | ||||
| 			to = to[n:] | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // SigExpired returns whether sig is a signature that has expired or is created | ||||
| // in the future. | ||||
| func (sig *Signature) SigExpired(currentTime time.Time) bool { | ||||
| 	if sig.CreationTime.After(currentTime) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if sig.SigLifetimeSecs == nil || *sig.SigLifetimeSecs == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	expiry := sig.CreationTime.Add(time.Duration(*sig.SigLifetimeSecs) * time.Second) | ||||
| 	return currentTime.After(expiry) | ||||
| } | ||||
|  | ||||
| // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. | ||||
| func (sig *Signature) buildHashSuffix(hashedSubpackets []byte) (err error) { | ||||
| 	hash, ok := s2k.HashToHashId(sig.Hash) | ||||
| 	if !ok { | ||||
| 		sig.HashSuffix = nil | ||||
| 		return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) | ||||
| 	} | ||||
|  | ||||
| 	hashedFields := bytes.NewBuffer([]byte{ | ||||
| 		uint8(sig.Version), | ||||
| 		uint8(sig.SigType), | ||||
| 		uint8(sig.PubKeyAlgo), | ||||
| 		uint8(hash), | ||||
| 		uint8(len(hashedSubpackets) >> 8), | ||||
| 		uint8(len(hashedSubpackets)), | ||||
| 	}) | ||||
| 	hashedFields.Write(hashedSubpackets) | ||||
|  | ||||
| 	var l uint64 = uint64(6 + len(hashedSubpackets)) | ||||
| 	if sig.Version == 5 { | ||||
| 		hashedFields.Write([]byte{0x05, 0xff}) | ||||
| 		hashedFields.Write([]byte{ | ||||
| 			uint8(l >> 56), uint8(l >> 48), uint8(l >> 40), uint8(l >> 32), | ||||
| 			uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l), | ||||
| 		}) | ||||
| 	} else { | ||||
| 		hashedFields.Write([]byte{0x04, 0xff}) | ||||
| 		hashedFields.Write([]byte{ | ||||
| 			uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l), | ||||
| 		}) | ||||
| 	} | ||||
| 	sig.HashSuffix = make([]byte, hashedFields.Len()) | ||||
| 	copy(sig.HashSuffix, hashedFields.Bytes()) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | ||||
| 	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) | ||||
| 	hashedSubpackets := make([]byte, hashedSubpacketsLen) | ||||
| 	serializeSubpackets(hashedSubpackets, sig.outSubpackets, true) | ||||
| 	err = sig.buildHashSuffix(hashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) { | ||||
| 		sig.AddMetadataToHashSuffix() | ||||
| 	} | ||||
|  | ||||
| 	h.Write(sig.HashSuffix) | ||||
| 	digest = h.Sum(nil) | ||||
| 	copy(sig.HashTag[:], digest) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Sign signs a message with a private key. The hash, h, must contain | ||||
| // the hash of the message to be signed and will be mutated by this function. | ||||
| // On success, the signature is stored in sig. Call Serialize to write it out. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { | ||||
| 	if priv.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	sig.Version = priv.PublicKey.Version | ||||
| 	sig.IssuerFingerprint = priv.PublicKey.Fingerprint | ||||
| 	sig.outSubpackets, err = sig.buildSubpackets(priv.PublicKey) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	digest, err := sig.signPrepareHash(h) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	switch priv.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		// supports both *rsa.PrivateKey and crypto.Signer | ||||
| 		sigdata, err := priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | ||||
| 		if err == nil { | ||||
| 			sig.RSASignature = encoding.NewMPI(sigdata) | ||||
| 		} | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) | ||||
|  | ||||
| 		// Need to truncate hashBytes to match FIPS 186-3 section 4.6. | ||||
| 		subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8 | ||||
| 		if len(digest) > subgroupSize { | ||||
| 			digest = digest[:subgroupSize] | ||||
| 		} | ||||
| 		r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) | ||||
| 		if err == nil { | ||||
| 			sig.DSASigR = new(encoding.MPI).SetBig(r) | ||||
| 			sig.DSASigS = new(encoding.MPI).SetBig(s) | ||||
| 		} | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		var r, s *big.Int | ||||
| 		if pk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok { | ||||
| 			// direct support, avoid asn1 wrapping/unwrapping | ||||
| 			r, s, err = ecdsa.Sign(config.Random(), pk, digest) | ||||
| 		} else { | ||||
| 			var b []byte | ||||
| 			b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | ||||
| 			if err == nil { | ||||
| 				r, s, err = unwrapECDSASig(b) | ||||
| 			} | ||||
| 		} | ||||
| 		if err == nil { | ||||
| 			sig.ECDSASigR = new(encoding.MPI).SetBig(r) | ||||
| 			sig.ECDSASigS = new(encoding.MPI).SetBig(s) | ||||
| 		} | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sigdata, err := priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, crypto.Hash(0)) | ||||
| 		if err == nil { | ||||
| 			sig.EdDSASigR = encoding.NewMPI(sigdata[:32]) | ||||
| 			sig.EdDSASigS = encoding.NewMPI(sigdata[32:]) | ||||
| 		} | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA | ||||
| // signature. | ||||
| func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { | ||||
| 	var ecsdaSig struct { | ||||
| 		R, S *big.Int | ||||
| 	} | ||||
| 	_, err = asn1.Unmarshal(b, &ecsdaSig) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return ecsdaSig.R, ecsdaSig.S, nil | ||||
| } | ||||
|  | ||||
| // SignUserId computes a signature from priv, asserting that pub is a valid | ||||
| // key for the identity id.  On success, the signature is stored in sig. Call | ||||
| // Serialize to write it out. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error { | ||||
| 	if priv.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	h, err := userIdSignatureHash(id, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
|  | ||||
| // CrossSignKey computes a signature from signingKey on pub hashed using hashKey. On success, | ||||
| // the signature is stored in sig. Call Serialize to write it out. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (sig *Signature) CrossSignKey(pub *PublicKey, hashKey *PublicKey, signingKey *PrivateKey, | ||||
| 	config *Config) error { | ||||
| 	h, err := keySignatureHash(hashKey, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, signingKey, config) | ||||
| } | ||||
|  | ||||
| // SignKey computes a signature from priv, asserting that pub is a subkey. On | ||||
| // success, the signature is stored in sig. Call Serialize to write it out. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error { | ||||
| 	if priv.Dummy() { | ||||
| 		return errors.ErrDummyPrivateKey("dummy key found") | ||||
| 	} | ||||
| 	h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
|  | ||||
| // RevokeKey computes a revocation signature of pub using priv. On success, the signature is | ||||
| // stored in sig. Call Serialize to write it out. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (sig *Signature) RevokeKey(pub *PublicKey, priv *PrivateKey, config *Config) error { | ||||
| 	h, err := keyRevocationHash(pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
|  | ||||
| // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | ||||
| // called first. | ||||
| func (sig *Signature) Serialize(w io.Writer) (err error) { | ||||
| 	if len(sig.outSubpackets) == 0 { | ||||
| 		sig.outSubpackets = sig.rawSubpackets | ||||
| 	} | ||||
| 	if sig.RSASignature == nil && sig.DSASigR == nil && sig.ECDSASigR == nil && sig.EdDSASigR == nil { | ||||
| 		return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | ||||
| 	} | ||||
|  | ||||
| 	sigLength := 0 | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		sigLength = int(sig.RSASignature.EncodedLength()) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		sigLength = int(sig.DSASigR.EncodedLength()) | ||||
| 		sigLength += int(sig.DSASigS.EncodedLength()) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		sigLength = int(sig.ECDSASigR.EncodedLength()) | ||||
| 		sigLength += int(sig.ECDSASigS.EncodedLength()) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sigLength = int(sig.EdDSASigR.EncodedLength()) | ||||
| 		sigLength += int(sig.EdDSASigS.EncodedLength()) | ||||
| 	default: | ||||
| 		panic("impossible") | ||||
| 	} | ||||
|  | ||||
| 	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) | ||||
| 	length := len(sig.HashSuffix) - 6 /* trailer not included */ + | ||||
| 		2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + | ||||
| 		2 /* hash tag */ + sigLength | ||||
| 	if sig.Version == 5 { | ||||
| 		length -= 4 // eight-octet instead of four-octet big endian | ||||
| 	} | ||||
| 	err = serializeHeader(w, packetTypeSignature, length) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = sig.serializeBody(w) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (sig *Signature) serializeBody(w io.Writer) (err error) { | ||||
| 	hashedSubpacketsLen := uint16(uint16(sig.HashSuffix[4])<<8) | uint16(sig.HashSuffix[5]) | ||||
| 	fields := sig.HashSuffix[:6+hashedSubpacketsLen] | ||||
| 	_, err = w.Write(fields) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) | ||||
| 	unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) | ||||
| 	unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) | ||||
| 	unhashedSubpackets[1] = byte(unhashedSubpacketsLen) | ||||
| 	serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false) | ||||
|  | ||||
| 	_, err = w.Write(unhashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(sig.HashTag[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		_, err = w.Write(sig.RSASignature.EncodedBytes()) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		if _, err = w.Write(sig.DSASigR.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(sig.DSASigS.EncodedBytes()) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		if _, err = w.Write(sig.ECDSASigR.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(sig.ECDSASigS.EncodedBytes()) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		if _, err = w.Write(sig.EdDSASigR.EncodedBytes()); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(sig.EdDSASigS.EncodedBytes()) | ||||
| 	default: | ||||
| 		panic("impossible") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // outputSubpacket represents a subpacket to be marshaled. | ||||
| type outputSubpacket struct { | ||||
| 	hashed        bool // true if this subpacket is in the hashed area. | ||||
| 	subpacketType signatureSubpacketType | ||||
| 	isCritical    bool | ||||
| 	contents      []byte | ||||
| } | ||||
|  | ||||
| func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubpacket, err error) { | ||||
| 	creationTime := make([]byte, 4) | ||||
| 	binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) | ||||
| 	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) | ||||
|  | ||||
| 	if sig.IssuerKeyId != nil && sig.Version == 4 { | ||||
| 		keyId := make([]byte, 8) | ||||
| 		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, true, keyId}) | ||||
| 	} | ||||
| 	if sig.IssuerFingerprint != nil { | ||||
| 		contents := append([]uint8{uint8(issuer.Version)}, sig.IssuerFingerprint...) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, issuerFingerprintSubpacket, true, contents}) | ||||
| 	} | ||||
| 	if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { | ||||
| 		sigLifetime := make([]byte, 4) | ||||
| 		binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime}) | ||||
| 	} | ||||
|  | ||||
| 	// Key flags may only appear in self-signatures or certification signatures. | ||||
|  | ||||
| 	if sig.FlagsValid { | ||||
| 		var flags byte | ||||
| 		if sig.FlagCertify { | ||||
| 			flags |= KeyFlagCertify | ||||
| 		} | ||||
| 		if sig.FlagSign { | ||||
| 			flags |= KeyFlagSign | ||||
| 		} | ||||
| 		if sig.FlagEncryptCommunications { | ||||
| 			flags |= KeyFlagEncryptCommunications | ||||
| 		} | ||||
| 		if sig.FlagEncryptStorage { | ||||
| 			flags |= KeyFlagEncryptStorage | ||||
| 		} | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) | ||||
| 	} | ||||
|  | ||||
| 	// The following subpackets may only appear in self-signatures. | ||||
|  | ||||
| 	var features = byte(0x00) | ||||
| 	if sig.MDC { | ||||
| 		features |= 0x01 | ||||
| 	} | ||||
| 	if sig.AEAD { | ||||
| 		features |= 0x02 | ||||
| 	} | ||||
| 	if sig.V5Keys { | ||||
| 		features |= 0x04 | ||||
| 	} | ||||
|  | ||||
| 	if features != 0x00 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, featuresSubpacket, false, []byte{features}}) | ||||
| 	} | ||||
|  | ||||
| 	if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 { | ||||
| 		keyLifetime := make([]byte, 4) | ||||
| 		binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime}) | ||||
| 	} | ||||
|  | ||||
| 	if sig.IsPrimaryId != nil && *sig.IsPrimaryId { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}}) | ||||
| 	} | ||||
|  | ||||
| 	if len(sig.PreferredSymmetric) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric}) | ||||
| 	} | ||||
|  | ||||
| 	if len(sig.PreferredHash) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash}) | ||||
| 	} | ||||
|  | ||||
| 	if len(sig.PreferredCompression) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) | ||||
| 	} | ||||
|  | ||||
| 	if len(sig.PolicyURI) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, policyUriSubpacket, false, []uint8(sig.PolicyURI)}) | ||||
| 	} | ||||
|  | ||||
| 	if len(sig.PreferredAEAD) > 0 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, prefAeadAlgosSubpacket, false, sig.PreferredAEAD}) | ||||
| 	} | ||||
|  | ||||
| 	// Revocation reason appears only in revocation signatures and is serialized as per section 5.2.3.23. | ||||
| 	if sig.RevocationReason != nil { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, reasonForRevocationSubpacket, true, | ||||
| 			append([]uint8{*sig.RevocationReason}, []uint8(sig.RevocationReasonText)...)}) | ||||
| 	} | ||||
|  | ||||
| 	// EmbeddedSignature appears only in subkeys capable of signing and is serialized as per section 5.2.3.26. | ||||
| 	if sig.EmbeddedSignature != nil { | ||||
| 		var buf bytes.Buffer | ||||
| 		err = sig.EmbeddedSignature.serializeBody(&buf) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, embeddedSignatureSubpacket, true, buf.Bytes()}) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // AddMetadataToHashSuffix modifies the current hash suffix to include metadata | ||||
| // (format, filename, and time). Version 5 keys protect this data including it | ||||
| // in the hash computation. See section 5.2.4. | ||||
| func (sig *Signature) AddMetadataToHashSuffix() { | ||||
| 	if sig == nil || sig.Version != 5 { | ||||
| 		return | ||||
| 	} | ||||
| 	if sig.SigType != 0x00 && sig.SigType != 0x01 { | ||||
| 		return | ||||
| 	} | ||||
| 	lit := sig.Metadata | ||||
| 	if lit == nil { | ||||
| 		// This will translate into six 0x00 bytes. | ||||
| 		lit = &LiteralData{} | ||||
| 	} | ||||
|  | ||||
| 	// Extract the current byte count | ||||
| 	n := sig.HashSuffix[len(sig.HashSuffix)-8:] | ||||
| 	l := uint64( | ||||
| 		uint64(n[0])<<56 | uint64(n[1])<<48 | uint64(n[2])<<40 | uint64(n[3])<<32 | | ||||
| 		uint64(n[4])<<24 | uint64(n[5])<<16 | uint64(n[6])<<8  | uint64(n[7])) | ||||
|  | ||||
| 	suffix := bytes.NewBuffer(nil) | ||||
| 	suffix.Write(sig.HashSuffix[:l]) | ||||
|  | ||||
| 	// Add the metadata | ||||
| 	var buf [4]byte | ||||
| 	buf[0] = lit.Format | ||||
| 	fileName := lit.FileName | ||||
| 	if len(lit.FileName) > 255 { | ||||
| 		fileName = fileName[:255] | ||||
| 	} | ||||
| 	buf[1] = byte(len(fileName)) | ||||
| 	suffix.Write(buf[:2]) | ||||
| 	suffix.Write([]byte(lit.FileName)) | ||||
| 	binary.BigEndian.PutUint32(buf[:], lit.Time) | ||||
| 	suffix.Write(buf[:]) | ||||
|  | ||||
| 	// Update the counter and restore trailing bytes | ||||
| 	l = uint64(suffix.Len()) | ||||
| 	suffix.Write([]byte{0x05, 0xff}) | ||||
| 	suffix.Write([]byte{ | ||||
| 		uint8(l >> 56), uint8(l >> 48), uint8(l >> 40), uint8(l >> 32), | ||||
| 		uint8(l >> 24), uint8(l >> 16), uint8(l >> 8), uint8(l), | ||||
| 	}) | ||||
| 	sig.HashSuffix = suffix.Bytes() | ||||
| } | ||||
							
								
								
									
										267
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/cipher" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/s2k" | ||||
| ) | ||||
|  | ||||
| // This is the largest session key that we'll support. Since no 512-bit cipher | ||||
| // has even been seriously used, this is comfortably large. | ||||
| const maxSessionKeySizeInBytes = 64 | ||||
|  | ||||
| // SymmetricKeyEncrypted represents a passphrase protected session key. See RFC | ||||
| // 4880, section 5.3. | ||||
| type SymmetricKeyEncrypted struct { | ||||
| 	Version      int | ||||
| 	CipherFunc   CipherFunction | ||||
| 	Mode         AEADMode | ||||
| 	s2k          func(out, in []byte) | ||||
| 	aeadNonce    []byte | ||||
| 	encryptedKey []byte | ||||
| } | ||||
|  | ||||
| func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { | ||||
| 	// RFC 4880, section 5.3. | ||||
| 	var buf [2]byte | ||||
| 	if _, err := readFull(r, buf[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	ske.Version = int(buf[0]) | ||||
| 	if ske.Version != 4 && ske.Version != 5 { | ||||
| 		return errors.UnsupportedError("unknown SymmetricKeyEncrypted version") | ||||
| 	} | ||||
| 	ske.CipherFunc = CipherFunction(buf[1]) | ||||
| 	if ske.CipherFunc.KeySize() == 0 { | ||||
| 		return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) | ||||
| 	} | ||||
|  | ||||
| 	if ske.Version == 5 { | ||||
| 		mode := make([]byte, 1) | ||||
| 		if _, err := r.Read(mode); err != nil { | ||||
| 			return errors.StructuralError("cannot read AEAD octect from packet") | ||||
| 		} | ||||
| 		ske.Mode = AEADMode(mode[0]) | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	if ske.s2k, err = s2k.Parse(r); err != nil { | ||||
| 		if _, ok := err.(errors.ErrDummyPrivateKey); ok { | ||||
| 			return errors.UnsupportedError("missing key GNU extension in session key") | ||||
| 		} | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if ske.Version == 5 { | ||||
| 		// AEAD nonce | ||||
| 		nonce := make([]byte, ske.Mode.NonceLength()) | ||||
| 		_, err := readFull(r, nonce) | ||||
| 		if err != nil && err != io.ErrUnexpectedEOF { | ||||
| 			return err | ||||
| 		} | ||||
| 		ske.aeadNonce = nonce | ||||
| 	} | ||||
|  | ||||
| 	encryptedKey := make([]byte, maxSessionKeySizeInBytes) | ||||
| 	// The session key may follow. We just have to try and read to find | ||||
| 	// out. If it exists then we limit it to maxSessionKeySizeInBytes. | ||||
| 	n, err := readFull(r, encryptedKey) | ||||
| 	if err != nil && err != io.ErrUnexpectedEOF { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if n != 0 { | ||||
| 		if n == maxSessionKeySizeInBytes { | ||||
| 			return errors.UnsupportedError("oversized encrypted session key") | ||||
| 		} | ||||
| 		ske.encryptedKey = encryptedKey[:n] | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Decrypt attempts to decrypt an encrypted session key and returns the key and | ||||
| // the cipher to use when decrypting a subsequent Symmetrically Encrypted Data | ||||
| // packet. | ||||
| func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) { | ||||
| 	key := make([]byte, ske.CipherFunc.KeySize()) | ||||
| 	ske.s2k(key, passphrase) | ||||
| 	if len(ske.encryptedKey) == 0 { | ||||
| 		return key, ske.CipherFunc, nil | ||||
| 	} | ||||
| 	switch ske.Version { | ||||
| 	case 4: | ||||
| 		plaintextKey, cipherFunc, err := ske.decryptV4(key) | ||||
| 		return plaintextKey, cipherFunc, err | ||||
| 	case 5: | ||||
| 		plaintextKey, err := ske.decryptV5(key) | ||||
| 		return plaintextKey, CipherFunction(0), err | ||||
| 	} | ||||
| 	err := errors.UnsupportedError("unknown SymmetricKeyEncrypted version") | ||||
| 	return nil, CipherFunction(0), err | ||||
| } | ||||
|  | ||||
| func (ske *SymmetricKeyEncrypted) decryptV4(key []byte) ([]byte, CipherFunction, error) { | ||||
| 	// the IV is all zeros | ||||
| 	iv := make([]byte, ske.CipherFunc.blockSize()) | ||||
| 	c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) | ||||
| 	plaintextKey := make([]byte, len(ske.encryptedKey)) | ||||
| 	c.XORKeyStream(plaintextKey, ske.encryptedKey) | ||||
| 	cipherFunc := CipherFunction(plaintextKey[0]) | ||||
| 	if cipherFunc.blockSize() == 0 { | ||||
| 		return nil, ske.CipherFunc, errors.UnsupportedError( | ||||
| 			"unknown cipher: " + strconv.Itoa(int(cipherFunc))) | ||||
| 	} | ||||
| 	plaintextKey = plaintextKey[1:] | ||||
| 	if len(plaintextKey) != cipherFunc.KeySize() { | ||||
| 		return nil, cipherFunc, errors.StructuralError( | ||||
| 			"length of decrypted key not equal to cipher keysize") | ||||
| 	} | ||||
| 	return plaintextKey, cipherFunc, nil | ||||
| } | ||||
|  | ||||
| func (ske *SymmetricKeyEncrypted) decryptV5(key []byte) ([]byte, error) { | ||||
| 	blockCipher := CipherFunction(ske.CipherFunc).new(key) | ||||
| 	aead := ske.Mode.new(blockCipher) | ||||
|  | ||||
| 	adata := []byte{0xc3, byte(5), byte(ske.CipherFunc), byte(ske.Mode)} | ||||
| 	plaintextKey, err := aead.Open(nil, ske.aeadNonce, ske.encryptedKey, adata) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return plaintextKey, nil | ||||
| } | ||||
|  | ||||
| // SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. | ||||
| // The packet contains a random session key, encrypted by a key derived from | ||||
| // the given passphrase. The session key is returned and must be passed to | ||||
| // SerializeSymmetricallyEncrypted or SerializeAEADEncrypted, depending on | ||||
| // whether config.AEADConfig != nil. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) { | ||||
| 	cipherFunc := config.Cipher() | ||||
| 	keySize := cipherFunc.KeySize() | ||||
| 	if keySize == 0 { | ||||
| 		return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) | ||||
| 	} | ||||
|  | ||||
| 	sessionKey := make([]byte, keySize) | ||||
| 	_, err = io.ReadFull(config.Random(), sessionKey) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err = SerializeSymmetricKeyEncryptedReuseKey(w, sessionKey, passphrase, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	key = sessionKey | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // SerializeSymmetricKeyEncryptedReuseKey serializes a symmetric key packet to w. | ||||
| // The packet contains the given session key, encrypted by a key derived from | ||||
| // the given passphrase. The session key must be passed to | ||||
| // SerializeSymmetricallyEncrypted or SerializeAEADEncrypted, depending on | ||||
| // whether config.AEADConfig != nil. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, config *Config) (err error) { | ||||
| 	var version int | ||||
| 	if config.AEAD() != nil { | ||||
| 		version = 5 | ||||
| 	} else { | ||||
| 		version = 4 | ||||
| 	} | ||||
| 	cipherFunc := config.Cipher() | ||||
| 	keySize := cipherFunc.KeySize() | ||||
| 	if keySize == 0 { | ||||
| 		return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) | ||||
| 	} | ||||
|  | ||||
| 	s2kBuf := new(bytes.Buffer) | ||||
| 	keyEncryptingKey := make([]byte, keySize) | ||||
| 	// s2k.Serialize salts and stretches the passphrase, and writes the | ||||
| 	// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf. | ||||
| 	err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s2kBytes := s2kBuf.Bytes() | ||||
|  | ||||
| 	var packetLength int | ||||
| 	switch version { | ||||
| 	case 4: | ||||
| 		packetLength = 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize | ||||
| 	case 5: | ||||
| 		nonceLen := config.AEAD().Mode().NonceLength() | ||||
| 		tagLen := config.AEAD().Mode().TagLength() | ||||
| 		packetLength = 3 + len(s2kBytes) + nonceLen + keySize + tagLen | ||||
| 	} | ||||
| 	err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	buf := make([]byte, 2) | ||||
| 	// Symmetric Key Encrypted Version | ||||
| 	buf[0] = byte(version) | ||||
| 	// Cipher function | ||||
| 	buf[1] = byte(cipherFunc) | ||||
|  | ||||
| 	if version == 5 { | ||||
| 		// AEAD mode | ||||
| 		buf = append(buf, byte(config.AEAD().Mode())) | ||||
| 	} | ||||
| 	_, err = w.Write(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(s2kBytes) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch version { | ||||
| 	case 4: | ||||
| 		iv := make([]byte, cipherFunc.blockSize()) | ||||
| 		c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv) | ||||
| 		encryptedCipherAndKey := make([]byte, keySize+1) | ||||
| 		c.XORKeyStream(encryptedCipherAndKey, buf[1:]) | ||||
| 		c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey) | ||||
| 		_, err = w.Write(encryptedCipherAndKey) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	case 5: | ||||
| 		blockCipher := cipherFunc.new(keyEncryptingKey) | ||||
| 		mode := config.AEAD().Mode() | ||||
| 		aead := mode.new(blockCipher) | ||||
| 		// Sample nonce using random reader | ||||
| 		nonce := make([]byte, config.AEAD().Mode().NonceLength()) | ||||
| 		_, err = io.ReadFull(config.Random(), nonce) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		// Seal and write (encryptedData includes auth. tag) | ||||
| 		adata := []byte{0xc3, byte(5), byte(cipherFunc), byte(mode)} | ||||
| 		encryptedData := aead.Seal(nil, nonce, sessionKey, adata) | ||||
| 		_, err = w.Write(nonce) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = w.Write(encryptedData) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										290
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,290 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/sha1" | ||||
| 	"crypto/subtle" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/ProtonMail/go-crypto/openpgp/errors" | ||||
| ) | ||||
|  | ||||
| // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The | ||||
| // encrypted Contents will consist of more OpenPGP packets. See RFC 4880, | ||||
| // sections 5.7 and 5.13. | ||||
| type SymmetricallyEncrypted struct { | ||||
| 	MDC      bool // true iff this is a type 18 packet and thus has an embedded MAC. | ||||
| 	Contents io.Reader | ||||
| 	prefix   []byte | ||||
| } | ||||
|  | ||||
| const symmetricallyEncryptedVersion = 1 | ||||
|  | ||||
| func (se *SymmetricallyEncrypted) parse(r io.Reader) error { | ||||
| 	if se.MDC { | ||||
| 		// See RFC 4880, section 5.13. | ||||
| 		var buf [1]byte | ||||
| 		_, err := readFull(r, buf[:]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if buf[0] != symmetricallyEncryptedVersion { | ||||
| 			return errors.UnsupportedError("unknown SymmetricallyEncrypted version") | ||||
| 		} | ||||
| 	} | ||||
| 	se.Contents = r | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Decrypt returns a ReadCloser, from which the decrypted Contents of the | ||||
| // packet can be read. An incorrect key will only be detected after trying | ||||
| // to decrypt the entire data. | ||||
| func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { | ||||
| 	keySize := c.KeySize() | ||||
| 	if keySize == 0 { | ||||
| 		return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) | ||||
| 	} | ||||
| 	if len(key) != keySize { | ||||
| 		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length") | ||||
| 	} | ||||
|  | ||||
| 	if se.prefix == nil { | ||||
| 		se.prefix = make([]byte, c.blockSize()+2) | ||||
| 		_, err := readFull(se.Contents, se.prefix) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} else if len(se.prefix) != c.blockSize()+2 { | ||||
| 		return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths") | ||||
| 	} | ||||
|  | ||||
| 	ocfbResync := OCFBResync | ||||
| 	if se.MDC { | ||||
| 		// MDC packets use a different form of OCFB mode. | ||||
| 		ocfbResync = OCFBNoResync | ||||
| 	} | ||||
|  | ||||
| 	s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) | ||||
|  | ||||
| 	plaintext := cipher.StreamReader{S: s, R: se.Contents} | ||||
|  | ||||
| 	if se.MDC { | ||||
| 		// MDC packets have an embedded hash that we need to check. | ||||
| 		h := sha1.New() | ||||
| 		h.Write(se.prefix) | ||||
| 		return &seMDCReader{in: plaintext, h: h}, nil | ||||
| 	} | ||||
|  | ||||
| 	// Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser. | ||||
| 	return seReader{plaintext}, nil | ||||
| } | ||||
|  | ||||
| // seReader wraps an io.Reader with a no-op Close method. | ||||
| type seReader struct { | ||||
| 	in io.Reader | ||||
| } | ||||
|  | ||||
| func (ser seReader) Read(buf []byte) (int, error) { | ||||
| 	return ser.in.Read(buf) | ||||
| } | ||||
|  | ||||
| func (ser seReader) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size | ||||
|  | ||||
| // An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold | ||||
| // of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an | ||||
| // MDC packet containing a hash of the previous Contents which is checked | ||||
| // against the running hash. See RFC 4880, section 5.13. | ||||
| type seMDCReader struct { | ||||
| 	in          io.Reader | ||||
| 	h           hash.Hash | ||||
| 	trailer     [mdcTrailerSize]byte | ||||
| 	scratch     [mdcTrailerSize]byte | ||||
| 	trailerUsed int | ||||
| 	error       bool | ||||
| 	eof         bool | ||||
| } | ||||
|  | ||||
| func (ser *seMDCReader) Read(buf []byte) (n int, err error) { | ||||
| 	if ser.error { | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 		return | ||||
| 	} | ||||
| 	if ser.eof { | ||||
| 		err = io.EOF | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// If we haven't yet filled the trailer buffer then we must do that | ||||
| 	// first. | ||||
| 	for ser.trailerUsed < mdcTrailerSize { | ||||
| 		n, err = ser.in.Read(ser.trailer[ser.trailerUsed:]) | ||||
| 		ser.trailerUsed += n | ||||
| 		if err == io.EOF { | ||||
| 			if ser.trailerUsed != mdcTrailerSize { | ||||
| 				n = 0 | ||||
| 				err = io.ErrUnexpectedEOF | ||||
| 				ser.error = true | ||||
| 				return | ||||
| 			} | ||||
| 			ser.eof = true | ||||
| 			n = 0 | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if err != nil { | ||||
| 			n = 0 | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// If it's a short read then we read into a temporary buffer and shift | ||||
| 	// the data into the caller's buffer. | ||||
| 	if len(buf) <= mdcTrailerSize { | ||||
| 		n, err = readFull(ser.in, ser.scratch[:len(buf)]) | ||||
| 		copy(buf, ser.trailer[:n]) | ||||
| 		ser.h.Write(buf[:n]) | ||||
| 		copy(ser.trailer[:], ser.trailer[n:]) | ||||
| 		copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:]) | ||||
| 		if n < len(buf) { | ||||
| 			ser.eof = true | ||||
| 			err = io.EOF | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	n, err = ser.in.Read(buf[mdcTrailerSize:]) | ||||
| 	copy(buf, ser.trailer[:]) | ||||
| 	ser.h.Write(buf[:n]) | ||||
| 	copy(ser.trailer[:], buf[n:]) | ||||
|  | ||||
| 	if err == io.EOF { | ||||
| 		ser.eof = true | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // This is a new-format packet tag byte for a type 19 (MDC) packet. | ||||
| const mdcPacketTagByte = byte(0x80) | 0x40 | 19 | ||||
|  | ||||
| func (ser *seMDCReader) Close() error { | ||||
| 	if ser.error { | ||||
| 		return errors.ErrMDCMissing | ||||
| 	} | ||||
|  | ||||
| 	for !ser.eof { | ||||
| 		// We haven't seen EOF so we need to read to the end | ||||
| 		var buf [1024]byte | ||||
| 		_, err := ser.Read(buf[:]) | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return errors.ErrMDCMissing | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ser.h.Write(ser.trailer[:2]) | ||||
|  | ||||
| 	final := ser.h.Sum(nil) | ||||
| 	if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { | ||||
| 		return errors.ErrMDCHashMismatch | ||||
| 	} | ||||
| 	// The hash already includes the MDC header, but we still check its value | ||||
| 	// to confirm encryption correctness | ||||
| 	if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { | ||||
| 		return errors.ErrMDCMissing | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // An seMDCWriter writes through to an io.WriteCloser while maintains a running | ||||
| // hash of the data written. On close, it emits an MDC packet containing the | ||||
| // running hash. | ||||
| type seMDCWriter struct { | ||||
| 	w io.WriteCloser | ||||
| 	h hash.Hash | ||||
| } | ||||
|  | ||||
| func (w *seMDCWriter) Write(buf []byte) (n int, err error) { | ||||
| 	w.h.Write(buf) | ||||
| 	return w.w.Write(buf) | ||||
| } | ||||
|  | ||||
| func (w *seMDCWriter) Close() (err error) { | ||||
| 	var buf [mdcTrailerSize]byte | ||||
|  | ||||
| 	buf[0] = mdcPacketTagByte | ||||
| 	buf[1] = sha1.Size | ||||
| 	w.h.Write(buf[:2]) | ||||
| 	digest := w.h.Sum(nil) | ||||
| 	copy(buf[2:], digest) | ||||
|  | ||||
| 	_, err = w.w.Write(buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return w.w.Close() | ||||
| } | ||||
|  | ||||
| // noOpCloser is like an ioutil.NopCloser, but for an io.Writer. | ||||
| type noOpCloser struct { | ||||
| 	w io.Writer | ||||
| } | ||||
|  | ||||
| func (c noOpCloser) Write(data []byte) (n int, err error) { | ||||
| 	return c.w.Write(data) | ||||
| } | ||||
|  | ||||
| func (c noOpCloser) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet | ||||
| // to w and returns a WriteCloser to which the to-be-encrypted packets can be | ||||
| // written. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (Contents io.WriteCloser, err error) { | ||||
| 	if c.KeySize() != len(key) { | ||||
| 		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") | ||||
| 	} | ||||
| 	writeCloser := noOpCloser{w} | ||||
| 	ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	block := c.new(key) | ||||
| 	blockSize := block.BlockSize() | ||||
| 	iv := make([]byte, blockSize) | ||||
| 	_, err = config.Random().Read(iv) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync) | ||||
| 	_, err = ciphertext.Write(prefix) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	plaintext := cipher.StreamWriter{S: s, W: ciphertext} | ||||
|  | ||||
| 	h := sha1.New() | ||||
| 	h.Write(iv) | ||||
| 	h.Write(iv[blockSize-2:]) | ||||
| 	Contents = &seMDCWriter{w: plaintext, h: h} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										94
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| // Copyright 2013 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"image" | ||||
| 	"image/jpeg" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| ) | ||||
|  | ||||
| const UserAttrImageSubpacket = 1 | ||||
|  | ||||
| // UserAttribute is capable of storing other types of data about a user | ||||
| // beyond name, email and a text comment. In practice, user attributes are typically used | ||||
| // to store a signed thumbnail photo JPEG image of the user. | ||||
| // See RFC 4880, section 5.12. | ||||
| type UserAttribute struct { | ||||
| 	Contents []*OpaqueSubpacket | ||||
| } | ||||
|  | ||||
| // NewUserAttributePhoto creates a user attribute packet | ||||
| // containing the given images. | ||||
| func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) { | ||||
| 	uat = new(UserAttribute) | ||||
| 	for _, photo := range photos { | ||||
| 		var buf bytes.Buffer | ||||
| 		// RFC 4880, Section 5.12.1. | ||||
| 		data := []byte{ | ||||
| 			0x10, 0x00, // Little-endian image header length (16 bytes) | ||||
| 			0x01,       // Image header version 1 | ||||
| 			0x01,       // JPEG | ||||
| 			0, 0, 0, 0, // 12 reserved octets, must be all zero. | ||||
| 			0, 0, 0, 0, | ||||
| 			0, 0, 0, 0} | ||||
| 		if _, err = buf.Write(data); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if err = jpeg.Encode(&buf, photo, nil); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		uat.Contents = append(uat.Contents, &OpaqueSubpacket{ | ||||
| 			SubType:  UserAttrImageSubpacket, | ||||
| 			Contents: buf.Bytes()}) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // NewUserAttribute creates a new user attribute packet containing the given subpackets. | ||||
| func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute { | ||||
| 	return &UserAttribute{Contents: contents} | ||||
| } | ||||
|  | ||||
| func (uat *UserAttribute) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.13 | ||||
| 	b, err := ioutil.ReadAll(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	uat.Contents, err = OpaqueSubpackets(b) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Serialize marshals the user attribute to w in the form of an OpenPGP packet, including | ||||
| // header. | ||||
| func (uat *UserAttribute) Serialize(w io.Writer) (err error) { | ||||
| 	var buf bytes.Buffer | ||||
| 	for _, sp := range uat.Contents { | ||||
| 		err = sp.Serialize(&buf) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(buf.Bytes()) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ImageData returns zero or more byte slices, each containing | ||||
| // JPEG File Interchange Format (JFIF), for each photo in the | ||||
| // user attribute packet. | ||||
| func (uat *UserAttribute) ImageData() (imageData [][]byte) { | ||||
| 	for _, sp := range uat.Contents { | ||||
| 		if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { | ||||
| 			imageData = append(imageData, sp.Contents[16:]) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										160
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| // 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 packet | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // UserId contains text that is intended to represent the name and email | ||||
| // address of the key holder. See RFC 4880, section 5.11. By convention, this | ||||
| // takes the form "Full Name (Comment) <email@example.com>" | ||||
| type UserId struct { | ||||
| 	Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below. | ||||
|  | ||||
| 	Name, Comment, Email string | ||||
| } | ||||
|  | ||||
| func hasInvalidCharacters(s string) bool { | ||||
| 	for _, c := range s { | ||||
| 		switch c { | ||||
| 		case '(', ')', '<', '>', 0: | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // NewUserId returns a UserId or nil if any of the arguments contain invalid | ||||
| // characters. The invalid characters are '\x00', '(', ')', '<' and '>' | ||||
| func NewUserId(name, comment, email string) *UserId { | ||||
| 	// RFC 4880 doesn't deal with the structure of userid strings; the | ||||
| 	// name, comment and email form is just a convention. However, there's | ||||
| 	// no convention about escaping the metacharacters and GPG just refuses | ||||
| 	// to create user ids where, say, the name contains a '('. We mirror | ||||
| 	// this behaviour. | ||||
|  | ||||
| 	if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	uid := new(UserId) | ||||
| 	uid.Name, uid.Comment, uid.Email = name, comment, email | ||||
| 	uid.Id = name | ||||
| 	if len(comment) > 0 { | ||||
| 		if len(uid.Id) > 0 { | ||||
| 			uid.Id += " " | ||||
| 		} | ||||
| 		uid.Id += "(" | ||||
| 		uid.Id += comment | ||||
| 		uid.Id += ")" | ||||
| 	} | ||||
| 	if len(email) > 0 { | ||||
| 		if len(uid.Id) > 0 { | ||||
| 			uid.Id += " " | ||||
| 		} | ||||
| 		uid.Id += "<" | ||||
| 		uid.Id += email | ||||
| 		uid.Id += ">" | ||||
| 	} | ||||
| 	return uid | ||||
| } | ||||
|  | ||||
| func (uid *UserId) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.11 | ||||
| 	b, err := ioutil.ReadAll(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	uid.Id = string(b) | ||||
| 	uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Serialize marshals uid to w in the form of an OpenPGP packet, including | ||||
| // header. | ||||
| func (uid *UserId) Serialize(w io.Writer) error { | ||||
| 	err := serializeHeader(w, packetTypeUserId, len(uid.Id)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write([]byte(uid.Id)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // parseUserId extracts the name, comment and email from a user id string that | ||||
| // is formatted as "Full Name (Comment) <email@example.com>". | ||||
| func parseUserId(id string) (name, comment, email string) { | ||||
| 	var n, c, e struct { | ||||
| 		start, end int | ||||
| 	} | ||||
| 	var state int | ||||
|  | ||||
| 	for offset, rune := range id { | ||||
| 		switch state { | ||||
| 		case 0: | ||||
| 			// Entering name | ||||
| 			n.start = offset | ||||
| 			state = 1 | ||||
| 			fallthrough | ||||
| 		case 1: | ||||
| 			// In name | ||||
| 			if rune == '(' { | ||||
| 				state = 2 | ||||
| 				n.end = offset | ||||
| 			} else if rune == '<' { | ||||
| 				state = 5 | ||||
| 				n.end = offset | ||||
| 			} | ||||
| 		case 2: | ||||
| 			// Entering comment | ||||
| 			c.start = offset | ||||
| 			state = 3 | ||||
| 			fallthrough | ||||
| 		case 3: | ||||
| 			// In comment | ||||
| 			if rune == ')' { | ||||
| 				state = 4 | ||||
| 				c.end = offset | ||||
| 			} | ||||
| 		case 4: | ||||
| 			// Between comment and email | ||||
| 			if rune == '<' { | ||||
| 				state = 5 | ||||
| 			} | ||||
| 		case 5: | ||||
| 			// Entering email | ||||
| 			e.start = offset | ||||
| 			state = 6 | ||||
| 			fallthrough | ||||
| 		case 6: | ||||
| 			// In email | ||||
| 			if rune == '>' { | ||||
| 				state = 7 | ||||
| 				e.end = offset | ||||
| 			} | ||||
| 		default: | ||||
| 			// After email | ||||
| 		} | ||||
| 	} | ||||
| 	switch state { | ||||
| 	case 1: | ||||
| 		// ended in the name | ||||
| 		n.end = len(id) | ||||
| 	case 3: | ||||
| 		// ended in comment | ||||
| 		c.end = len(id) | ||||
| 	case 6: | ||||
| 		// ended in email | ||||
| 		e.end = len(id) | ||||
| 	} | ||||
|  | ||||
| 	name = strings.TrimSpace(id[n.start:n.end]) | ||||
| 	comment = strings.TrimSpace(id[c.start:c.end]) | ||||
| 	email = strings.TrimSpace(id[e.start:e.end]) | ||||
| 	return | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Norwin
					Norwin