mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	Switch to keybase go-crypto (for some elliptic curve key) + test (#1925)
* Switch to keybase go-crypto (for some elliptic curve key) + test
* Use assert.NoError 
and add a little more context to failing test description
* Use assert.(No)Error everywhere 🌈
and assert.Error in place of .Nil/.NotNil
			
			
This commit is contained in:
		
				
					committed by
					
						 Lunny Xiao
						Lunny Xiao
					
				
			
			
				
	
			
			
			
						parent
						
							5e92b82ac6
						
					
				
				
					commit
					274149dd14
				
			
							
								
								
									
										237
									
								
								vendor/github.com/keybase/go-crypto/openpgp/armor/armor.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								vendor/github.com/keybase/go-crypto/openpgp/armor/armor.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | ||||
| // 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. | ||||
|  | ||||
| // Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is | ||||
| // very similar to PEM except that it has an additional CRC checksum. | ||||
| package armor // import "github.com/keybase/go-crypto/openpgp/armor" | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"encoding/base64" | ||||
| 	"io" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| ) | ||||
|  | ||||
| // A Block represents an OpenPGP armored structure. | ||||
| // | ||||
| // The encoded form is: | ||||
| //    -----BEGIN Type----- | ||||
| //    Headers | ||||
| // | ||||
| //    base64-encoded Bytes | ||||
| //    '=' base64 encoded checksum | ||||
| //    -----END Type----- | ||||
| // where Headers is a possibly empty sequence of Key: Value lines. | ||||
| // | ||||
| // Since the armored data can be very large, this package presents a streaming | ||||
| // interface. | ||||
| type Block struct { | ||||
| 	Type    string            // The type, taken from the preamble (i.e. "PGP SIGNATURE"). | ||||
| 	Header  map[string]string // Optional headers. | ||||
| 	Body    io.Reader         // A Reader from which the contents can be read | ||||
| 	lReader lineReader | ||||
| 	oReader openpgpReader | ||||
| } | ||||
|  | ||||
| var ArmorCorrupt error = errors.StructuralError("armor invalid") | ||||
|  | ||||
| const crc24Init = 0xb704ce | ||||
| const crc24Poly = 0x1864cfb | ||||
| const crc24Mask = 0xffffff | ||||
|  | ||||
| // crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1 | ||||
| func crc24(crc uint32, d []byte) uint32 { | ||||
| 	for _, b := range d { | ||||
| 		crc ^= uint32(b) << 16 | ||||
| 		for i := 0; i < 8; i++ { | ||||
| 			crc <<= 1 | ||||
| 			if crc&0x1000000 != 0 { | ||||
| 				crc ^= crc24Poly | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return crc | ||||
| } | ||||
|  | ||||
| var armorStart = []byte("-----BEGIN ") | ||||
| var armorEnd = []byte("-----END ") | ||||
| var armorEndOfLine = []byte("-----") | ||||
|  | ||||
| // lineReader wraps a line based reader. It watches for the end of an armor | ||||
| // block and records the expected CRC value. | ||||
| type lineReader struct { | ||||
| 	in  *bufio.Reader | ||||
| 	buf []byte | ||||
| 	eof bool | ||||
| 	crc *uint32 | ||||
| } | ||||
|  | ||||
| // ourIsSpace checks if a rune is either space according to unicode | ||||
| // package, or ZeroWidthSpace (which is not a space according to | ||||
| // unicode module). Used to trim lines during header reading. | ||||
| func ourIsSpace(r rune) bool { | ||||
| 	return r == '\u200b' || unicode.IsSpace(r) | ||||
| } | ||||
|  | ||||
| func (l *lineReader) Read(p []byte) (n int, err error) { | ||||
| 	if l.eof { | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
|  | ||||
| 	if len(l.buf) > 0 { | ||||
| 		n = copy(p, l.buf) | ||||
| 		l.buf = l.buf[n:] | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	line, _, err := l.in.ReadLine() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	line = bytes.TrimFunc(line, ourIsSpace) | ||||
|  | ||||
| 	if len(line) == 5 && line[0] == '=' { | ||||
| 		// This is the checksum line | ||||
| 		var expectedBytes [3]byte | ||||
| 		var m int | ||||
| 		m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:]) | ||||
| 		if m != 3 || err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		crc := uint32(expectedBytes[0])<<16 | | ||||
| 			uint32(expectedBytes[1])<<8 | | ||||
| 			uint32(expectedBytes[2]) | ||||
| 		l.crc = &crc | ||||
|  | ||||
| 		for { | ||||
| 			line, _, err = l.in.ReadLine() | ||||
| 			if err != nil && err != io.EOF { | ||||
| 				return | ||||
| 			} | ||||
| 			if len(strings.TrimSpace(string(line))) > 0 { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if !bytes.HasPrefix(line, armorEnd) { | ||||
| 			return 0, ArmorCorrupt | ||||
| 		} | ||||
|  | ||||
| 		l.eof = true | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
|  | ||||
| 	if bytes.HasPrefix(line, armorEnd) { | ||||
| 		// Unexpected ending, there was no checksum. | ||||
| 		l.eof = true | ||||
| 		l.crc = nil | ||||
| 		return 0, io.EOF | ||||
| 	} | ||||
|  | ||||
| 	n = copy(p, line) | ||||
| 	bytesToSave := len(line) - n | ||||
| 	if bytesToSave > 0 { | ||||
| 		if cap(l.buf) < bytesToSave { | ||||
| 			l.buf = make([]byte, 0, bytesToSave) | ||||
| 		} | ||||
| 		l.buf = l.buf[0:bytesToSave] | ||||
| 		copy(l.buf, line[n:]) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // openpgpReader passes Read calls to the underlying base64 decoder, but keeps | ||||
| // a running CRC of the resulting data and checks the CRC against the value | ||||
| // found by the lineReader at EOF. | ||||
| type openpgpReader struct { | ||||
| 	lReader    *lineReader | ||||
| 	b64Reader  io.Reader | ||||
| 	currentCRC uint32 | ||||
| } | ||||
|  | ||||
| func (r *openpgpReader) Read(p []byte) (n int, err error) { | ||||
| 	n, err = r.b64Reader.Read(p) | ||||
| 	r.currentCRC = crc24(r.currentCRC, p[:n]) | ||||
|  | ||||
| 	if err == io.EOF { | ||||
| 		if r.lReader.crc != nil && *r.lReader.crc != uint32(r.currentCRC&crc24Mask) { | ||||
| 			return 0, ArmorCorrupt | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Decode reads a PGP armored block from the given Reader. It will ignore | ||||
| // leading garbage. If it doesn't find a block, it will return nil, io.EOF. The | ||||
| // given Reader is not usable after calling this function: an arbitrary amount | ||||
| // of data may have been read past the end of the block. | ||||
| func Decode(in io.Reader) (p *Block, err error) { | ||||
| 	r := bufio.NewReaderSize(in, 100) | ||||
| 	var line []byte | ||||
| 	ignoreNext := false | ||||
|  | ||||
| TryNextBlock: | ||||
| 	p = nil | ||||
|  | ||||
| 	// Skip leading garbage | ||||
| 	for { | ||||
| 		ignoreThis := ignoreNext | ||||
| 		line, ignoreNext, err = r.ReadLine() | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if ignoreNext || ignoreThis { | ||||
| 			continue | ||||
| 		} | ||||
| 		line = bytes.TrimSpace(line) | ||||
| 		if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	p = new(Block) | ||||
| 	p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)]) | ||||
| 	p.Header = make(map[string]string) | ||||
| 	nextIsContinuation := false | ||||
| 	var lastKey string | ||||
|  | ||||
| 	// Read headers | ||||
| 	for { | ||||
| 		isContinuation := nextIsContinuation | ||||
| 		line, nextIsContinuation, err = r.ReadLine() | ||||
| 		if err != nil { | ||||
| 			p = nil | ||||
| 			return | ||||
| 		} | ||||
| 		if isContinuation { | ||||
| 			p.Header[lastKey] += string(line) | ||||
| 			continue | ||||
| 		} | ||||
| 		line = bytes.TrimFunc(line, ourIsSpace) | ||||
| 		if len(line) == 0 { | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		i := bytes.Index(line, []byte(": ")) | ||||
| 		if i == -1 { | ||||
| 			goto TryNextBlock | ||||
| 		} | ||||
| 		lastKey = string(line[:i]) | ||||
| 		p.Header[lastKey] = string(line[i+2:]) | ||||
| 	} | ||||
|  | ||||
| 	p.lReader.in = r | ||||
| 	p.oReader.currentCRC = crc24Init | ||||
| 	p.oReader.lReader = &p.lReader | ||||
| 	p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader) | ||||
| 	p.Body = &p.oReader | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										160
									
								
								vendor/github.com/keybase/go-crypto/openpgp/armor/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/keybase/go-crypto/openpgp/armor/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| // 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. | ||||
|  | ||||
| package armor | ||||
|  | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| var armorHeaderSep = []byte(": ") | ||||
| var blockEnd = []byte("\n=") | ||||
| var newline = []byte("\n") | ||||
| var armorEndOfLineOut = []byte("-----\n") | ||||
|  | ||||
| // writeSlices writes its arguments to the given Writer. | ||||
| func writeSlices(out io.Writer, slices ...[]byte) (err error) { | ||||
| 	for _, s := range slices { | ||||
| 		_, err = out.Write(s) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // lineBreaker breaks data across several lines, all of the same byte length | ||||
| // (except possibly the last). Lines are broken with a single '\n'. | ||||
| type lineBreaker struct { | ||||
| 	lineLength  int | ||||
| 	line        []byte | ||||
| 	used        int | ||||
| 	out         io.Writer | ||||
| 	haveWritten bool | ||||
| } | ||||
|  | ||||
| func newLineBreaker(out io.Writer, lineLength int) *lineBreaker { | ||||
| 	return &lineBreaker{ | ||||
| 		lineLength: lineLength, | ||||
| 		line:       make([]byte, lineLength), | ||||
| 		used:       0, | ||||
| 		out:        out, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (l *lineBreaker) Write(b []byte) (n int, err error) { | ||||
| 	n = len(b) | ||||
|  | ||||
| 	if n == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if l.used == 0 && l.haveWritten { | ||||
| 		_, err = l.out.Write([]byte{'\n'}) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if l.used+len(b) < l.lineLength { | ||||
| 		l.used += copy(l.line[l.used:], b) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	l.haveWritten = true | ||||
| 	_, err = l.out.Write(l.line[0:l.used]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	excess := l.lineLength - l.used | ||||
| 	l.used = 0 | ||||
|  | ||||
| 	_, err = l.out.Write(b[0:excess]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, err = l.Write(b[excess:]) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (l *lineBreaker) Close() (err error) { | ||||
| 	if l.used > 0 { | ||||
| 		_, err = l.out.Write(l.line[0:l.used]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // encoding keeps track of a running CRC24 over the data which has been written | ||||
| // to it and outputs a OpenPGP checksum when closed, followed by an armor | ||||
| // trailer. | ||||
| // | ||||
| // It's built into a stack of io.Writers: | ||||
| //    encoding -> base64 encoder -> lineBreaker -> out | ||||
| type encoding struct { | ||||
| 	out       io.Writer | ||||
| 	breaker   *lineBreaker | ||||
| 	b64       io.WriteCloser | ||||
| 	crc       uint32 | ||||
| 	blockType []byte | ||||
| } | ||||
|  | ||||
| func (e *encoding) Write(data []byte) (n int, err error) { | ||||
| 	e.crc = crc24(e.crc, data) | ||||
| 	return e.b64.Write(data) | ||||
| } | ||||
|  | ||||
| func (e *encoding) Close() (err error) { | ||||
| 	err = e.b64.Close() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	e.breaker.Close() | ||||
|  | ||||
| 	var checksumBytes [3]byte | ||||
| 	checksumBytes[0] = byte(e.crc >> 16) | ||||
| 	checksumBytes[1] = byte(e.crc >> 8) | ||||
| 	checksumBytes[2] = byte(e.crc) | ||||
|  | ||||
| 	var b64ChecksumBytes [4]byte | ||||
| 	base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:]) | ||||
|  | ||||
| 	return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine, []byte{'\n'}) | ||||
| } | ||||
|  | ||||
| // Encode returns a WriteCloser which will encode the data written to it in | ||||
| // OpenPGP armor. | ||||
| func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) { | ||||
| 	bType := []byte(blockType) | ||||
| 	err = writeSlices(out, armorStart, bType, armorEndOfLineOut) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	for k, v := range headers { | ||||
| 		err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	_, err = out.Write(newline) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	e := &encoding{ | ||||
| 		out:       out, | ||||
| 		breaker:   newLineBreaker(out, 64), | ||||
| 		crc:       crc24Init, | ||||
| 		blockType: bType, | ||||
| 	} | ||||
| 	e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker) | ||||
| 	return e, nil | ||||
| } | ||||
							
								
								
									
										59
									
								
								vendor/github.com/keybase/go-crypto/openpgp/canonical_text.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/keybase/go-crypto/openpgp/canonical_text.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| // Copyright 2011 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package openpgp | ||||
|  | ||||
| import "hash" | ||||
|  | ||||
| // NewCanonicalTextHash reformats text written to it into the canonical | ||||
| // form and then applies the hash h.  See RFC 4880, section 5.2.1. | ||||
| func NewCanonicalTextHash(h hash.Hash) hash.Hash { | ||||
| 	return &canonicalTextHash{h, 0} | ||||
| } | ||||
|  | ||||
| type canonicalTextHash struct { | ||||
| 	h hash.Hash | ||||
| 	s int | ||||
| } | ||||
|  | ||||
| var newline = []byte{'\r', '\n'} | ||||
|  | ||||
| func (cth *canonicalTextHash) Write(buf []byte) (int, error) { | ||||
| 	start := 0 | ||||
|  | ||||
| 	for i, c := range buf { | ||||
| 		switch cth.s { | ||||
| 		case 0: | ||||
| 			if c == '\r' { | ||||
| 				cth.s = 1 | ||||
| 			} else if c == '\n' { | ||||
| 				cth.h.Write(buf[start:i]) | ||||
| 				cth.h.Write(newline) | ||||
| 				start = i + 1 | ||||
| 			} | ||||
| 		case 1: | ||||
| 			cth.s = 0 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	cth.h.Write(buf[start:]) | ||||
| 	return len(buf), nil | ||||
| } | ||||
|  | ||||
| func (cth *canonicalTextHash) Sum(in []byte) []byte { | ||||
| 	return cth.h.Sum(in) | ||||
| } | ||||
|  | ||||
| func (cth *canonicalTextHash) Reset() { | ||||
| 	cth.h.Reset() | ||||
| 	cth.s = 0 | ||||
| } | ||||
|  | ||||
| func (cth *canonicalTextHash) Size() int { | ||||
| 	return cth.h.Size() | ||||
| } | ||||
|  | ||||
| func (cth *canonicalTextHash) BlockSize() int { | ||||
| 	return cth.h.BlockSize() | ||||
| } | ||||
							
								
								
									
										282
									
								
								vendor/github.com/keybase/go-crypto/openpgp/ecdh/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								vendor/github.com/keybase/go-crypto/openpgp/ecdh/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,282 @@ | ||||
| package ecdh | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto" | ||||
| 	"crypto/aes" | ||||
| 	"crypto/elliptic" | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"github.com/keybase/go-crypto/curve25519" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| ) | ||||
|  | ||||
| type PublicKey struct { | ||||
| 	elliptic.Curve | ||||
| 	X, Y *big.Int | ||||
| } | ||||
|  | ||||
| type PrivateKey struct { | ||||
| 	PublicKey | ||||
| 	X *big.Int | ||||
| } | ||||
|  | ||||
| // KDF implements Key Derivation Function as described in | ||||
| // https://tools.ietf.org/html/rfc6637#section-7 | ||||
| func (e *PublicKey) KDF(S []byte, kdfParams []byte, hash crypto.Hash) []byte { | ||||
| 	sLen := (e.Curve.Params().P.BitLen() + 7) / 8 | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	buf.Write([]byte{0, 0, 0, 1}) | ||||
| 	if sLen > len(S) { | ||||
| 		// zero-pad the S. If we got invalid S (bigger than curve's | ||||
| 		// P), we are going to produce invalid key. Garbage in, | ||||
| 		// garbage out. | ||||
| 		buf.Write(make([]byte, sLen-len(S))) | ||||
| 	} | ||||
| 	buf.Write(S) | ||||
| 	buf.Write(kdfParams) | ||||
|  | ||||
| 	hashw := hash.New() | ||||
|  | ||||
| 	hashw.Write(buf.Bytes()) | ||||
| 	key := hashw.Sum(nil) | ||||
|  | ||||
| 	return key | ||||
| } | ||||
|  | ||||
| // AESKeyUnwrap implements RFC 3394 Key Unwrapping. See | ||||
| // http://tools.ietf.org/html/rfc3394#section-2.2.1 | ||||
| // Note: The second described algorithm ("index-based") is implemented | ||||
| // here. | ||||
| func AESKeyUnwrap(key, cipherText []byte) ([]byte, error) { | ||||
| 	if len(cipherText)%8 != 0 { | ||||
| 		return nil, errors.New("cipherText must by a multiple of 64 bits") | ||||
| 	} | ||||
|  | ||||
| 	cipher, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	nblocks := len(cipherText)/8 - 1 | ||||
|  | ||||
| 	// 1) Initialize variables. | ||||
| 	// - Set A = C[0] | ||||
| 	var A [aes.BlockSize]byte | ||||
| 	copy(A[:8], cipherText[:8]) | ||||
|  | ||||
| 	// For i = 1 to n | ||||
| 	//   Set R[i] = C[i] | ||||
| 	R := make([]byte, len(cipherText)-8) | ||||
| 	copy(R, cipherText[8:]) | ||||
|  | ||||
| 	// 2) Compute intermediate values. | ||||
| 	for j := 5; j >= 0; j-- { | ||||
| 		for i := nblocks - 1; i >= 0; i-- { | ||||
| 			// B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i | ||||
| 			// A = MSB(64, B) | ||||
| 			t := uint64(nblocks*j + i + 1) | ||||
| 			At := binary.BigEndian.Uint64(A[:8]) ^ t | ||||
| 			binary.BigEndian.PutUint64(A[:8], At) | ||||
|  | ||||
| 			copy(A[8:], R[i*8:i*8+8]) | ||||
| 			cipher.Decrypt(A[:], A[:]) | ||||
|  | ||||
| 			// R[i] = LSB(B, 64) | ||||
| 			copy(R[i*8:i*8+8], A[8:]) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// 3) Output results. | ||||
| 	// If A is an appropriate initial value (see 2.2.3), | ||||
| 	for i := 0; i < 8; i++ { | ||||
| 		if A[i] != 0xA6 { | ||||
| 			return nil, errors.New("Failed to unwrap key (A is not IV)") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return R, nil | ||||
| } | ||||
|  | ||||
| // AESKeyWrap implements RFC 3394 Key Wrapping. See | ||||
| // https://tools.ietf.org/html/rfc3394#section-2.2.2 | ||||
| // Note: The second described algorithm ("index-based") is implemented | ||||
| // here. | ||||
| func AESKeyWrap(key, plainText []byte) ([]byte, error) { | ||||
| 	if len(plainText)%8 != 0 { | ||||
| 		return nil, errors.New("plainText must be a multiple of 64 bits") | ||||
| 	} | ||||
|  | ||||
| 	cipher, err := aes.NewCipher(key) // NewCipher checks key size | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	nblocks := len(plainText) / 8 | ||||
|  | ||||
| 	// 1) Initialize variables. | ||||
| 	var A [aes.BlockSize]byte | ||||
| 	// Section 2.2.3.1 -- Initial Value | ||||
| 	// http://tools.ietf.org/html/rfc3394#section-2.2.3.1 | ||||
| 	for i := 0; i < 8; i++ { | ||||
| 		A[i] = 0xA6 | ||||
| 	} | ||||
|  | ||||
| 	// For i = 1 to n | ||||
| 	//   Set R[i] = P[i] | ||||
| 	R := make([]byte, len(plainText)) | ||||
| 	copy(R, plainText) | ||||
|  | ||||
| 	// 2) Calculate intermediate values. | ||||
| 	for j := 0; j <= 5; j++ { | ||||
| 		for i := 0; i < nblocks; i++ { | ||||
| 			// B = AES(K, A | R[i]) | ||||
| 			copy(A[8:], R[i*8:i*8+8]) | ||||
| 			cipher.Encrypt(A[:], A[:]) | ||||
|  | ||||
| 			// (Assume B = A) | ||||
| 			// A = MSB(64, B) ^ t where t = (n*j)+1 | ||||
| 			t := uint64(j*nblocks + i + 1) | ||||
| 			At := binary.BigEndian.Uint64(A[:8]) ^ t | ||||
| 			binary.BigEndian.PutUint64(A[:8], At) | ||||
|  | ||||
| 			// R[i] = LSB(64, B) | ||||
| 			copy(R[i*8:i*8+8], A[8:]) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// 3) Output results. | ||||
| 	// Set C[0] = A | ||||
| 	// For i = 1 to n | ||||
| 	//   C[i] = R[i] | ||||
| 	return append(A[:8], R...), nil | ||||
| } | ||||
|  | ||||
| // PadBuffer pads byte buffer buf to a length being multiple of | ||||
| // blockLen. Additional bytes appended to the buffer have value of the | ||||
| // number padded bytes. E.g. if the buffer is 3 bytes short of being | ||||
| // 40 bytes total, the appended bytes will be [03, 03, 03]. | ||||
| func PadBuffer(buf []byte, blockLen int) []byte { | ||||
| 	padding := blockLen - (len(buf) % blockLen) | ||||
| 	if padding == 0 { | ||||
| 		return buf | ||||
| 	} | ||||
|  | ||||
| 	padBuf := make([]byte, padding) | ||||
| 	for i := 0; i < padding; i++ { | ||||
| 		padBuf[i] = byte(padding) | ||||
| 	} | ||||
|  | ||||
| 	return append(buf, padBuf...) | ||||
| } | ||||
|  | ||||
| // UnpadBuffer verifies that buffer contains proper padding and | ||||
| // returns buffer without the padding, or nil if the padding was | ||||
| // invalid. | ||||
| func UnpadBuffer(buf []byte, dataLen int) []byte { | ||||
| 	padding := len(buf) - dataLen | ||||
| 	outBuf := buf[:dataLen] | ||||
|  | ||||
| 	for i := dataLen; i < len(buf); i++ { | ||||
| 		if buf[i] != byte(padding) { | ||||
| 			// Invalid padding - bail out | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return outBuf | ||||
| } | ||||
|  | ||||
| func (e *PublicKey) Encrypt(random io.Reader, kdfParams []byte, plain []byte, hash crypto.Hash, kdfKeySize int) (Vx *big.Int, Vy *big.Int, C []byte, err error) { | ||||
| 	// Vx, Vy - encryption key | ||||
|  | ||||
| 	// Note for Curve 25519 - curve25519 library already does key | ||||
| 	// clamping in scalarMult, so we can use generic random scalar | ||||
| 	// generation from elliptic. | ||||
| 	priv, Vx, Vy, err := elliptic.GenerateKey(e.Curve, random) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Sx, Sy - shared secret | ||||
| 	Sx, _ := e.Curve.ScalarMult(e.X, e.Y, priv) | ||||
|  | ||||
| 	// Encrypt the payload with KDF-ed S as the encryption key. Pass | ||||
| 	// the ciphertext along with V to the recipient. Recipient can | ||||
| 	// generate S using V and their priv key, and then KDF(S), on | ||||
| 	// their own, to get encryption key and decrypt the ciphertext, | ||||
| 	// revealing encryption key for symmetric encryption later. | ||||
|  | ||||
| 	plain = PadBuffer(plain, 8) | ||||
| 	key := e.KDF(Sx.Bytes(), kdfParams, hash) | ||||
|  | ||||
| 	// Take only as many bytes from key as the key length (the hash | ||||
| 	// result might be bigger) | ||||
| 	encrypted, err := AESKeyWrap(key[:kdfKeySize], plain) | ||||
|  | ||||
| 	return Vx, Vy, encrypted, nil | ||||
| } | ||||
|  | ||||
| func (e *PrivateKey) DecryptShared(X, Y *big.Int) []byte { | ||||
| 	Sx, _ := e.Curve.ScalarMult(X, Y, e.X.Bytes()) | ||||
| 	return Sx.Bytes() | ||||
| } | ||||
|  | ||||
| func countBits(buffer []byte) int { | ||||
| 	var headerLen int | ||||
| 	switch buffer[0] { | ||||
| 	case 0x4: | ||||
| 		headerLen = 3 | ||||
| 	case 0x40: | ||||
| 		headerLen = 7 | ||||
| 	default: | ||||
| 		// Unexpected header - but we can still count the bits. | ||||
| 		val := buffer[0] | ||||
| 		headerLen = 0 | ||||
| 		for val > 0 { | ||||
| 			val = val / 2 | ||||
| 			headerLen++ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return headerLen + (len(buffer)-1)*8 | ||||
| } | ||||
|  | ||||
| // elliptic.Marshal and elliptic.Unmarshal only marshals uncompressed | ||||
| // 0x4 MPI types. These functions will check if the curve is cv25519, | ||||
| // and if so, use 0x40 compressed type to (un)marshal. Otherwise, | ||||
| // elliptic.(Un)marshal will be called. | ||||
|  | ||||
| // Marshal encodes point into either 0x4 uncompressed point form, or | ||||
| // 0x40 compressed point for Curve 25519. | ||||
| func Marshal(curve elliptic.Curve, x, y *big.Int) (buf []byte, bitSize int) { | ||||
| 	// NOTE: Read more about MPI encoding in the RFC: | ||||
| 	// https://tools.ietf.org/html/rfc4880#section-3.2 | ||||
|  | ||||
| 	// We are required to encode size in bits, counting from the most- | ||||
| 	// significant non-zero bit. So assuming that the buffer never | ||||
| 	// starts with 0x00, we only need to count bits in the first byte | ||||
| 	// - and in current implentation it will always be 0x4 or 0x40. | ||||
|  | ||||
| 	cv, ok := curve25519.ToCurve25519(curve) | ||||
| 	if ok { | ||||
| 		buf = cv.MarshalType40(x, y) | ||||
| 	} else { | ||||
| 		buf = elliptic.Marshal(curve, x, y) | ||||
| 	} | ||||
|  | ||||
| 	return buf, countBits(buf) | ||||
| } | ||||
|  | ||||
| // Unmarshal converts point, serialized by Marshal, into x, y pair. | ||||
| // For 0x40 compressed points (for Curve 25519), y will always be 0. | ||||
| // It is an error if point is not on the curve, On error, x = nil. | ||||
| func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) { | ||||
| 	cv, ok := curve25519.ToCurve25519(curve) | ||||
| 	if ok { | ||||
| 		return cv.UnmarshalType40(data) | ||||
| 	} | ||||
|  | ||||
| 	return elliptic.Unmarshal(curve, data) | ||||
| } | ||||
							
								
								
									
										122
									
								
								vendor/github.com/keybase/go-crypto/openpgp/elgamal/elgamal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								vendor/github.com/keybase/go-crypto/openpgp/elgamal/elgamal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| // 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 elgamal implements ElGamal encryption, suitable for OpenPGP, | ||||
| // as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on | ||||
| // Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31, | ||||
| // n. 4, 1985, pp. 469-472. | ||||
| // | ||||
| // This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it | ||||
| // unsuitable for other protocols. RSA should be used in preference in any | ||||
| // case. | ||||
| package elgamal // import "github.com/keybase/go-crypto/openpgp/elgamal" | ||||
|  | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"crypto/subtle" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| ) | ||||
|  | ||||
| // PublicKey represents an ElGamal public key. | ||||
| type PublicKey struct { | ||||
| 	G, P, Y *big.Int | ||||
| } | ||||
|  | ||||
| // PrivateKey represents an ElGamal private key. | ||||
| type PrivateKey struct { | ||||
| 	PublicKey | ||||
| 	X *big.Int | ||||
| } | ||||
|  | ||||
| // Encrypt encrypts the given message to the given public key. The result is a | ||||
| // pair of integers. Errors can result from reading random, or because msg is | ||||
| // too large to be encrypted to the public key. | ||||
| func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) { | ||||
| 	pLen := (pub.P.BitLen() + 7) / 8 | ||||
| 	if len(msg) > pLen-11 { | ||||
| 		err = errors.New("elgamal: message too long") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// EM = 0x02 || PS || 0x00 || M | ||||
| 	em := make([]byte, pLen-1) | ||||
| 	em[0] = 2 | ||||
| 	ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] | ||||
| 	err = nonZeroRandomBytes(ps, random) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	em[len(em)-len(msg)-1] = 0 | ||||
| 	copy(mm, msg) | ||||
|  | ||||
| 	m := new(big.Int).SetBytes(em) | ||||
|  | ||||
| 	k, err := rand.Int(random, pub.P) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c1 = new(big.Int).Exp(pub.G, k, pub.P) | ||||
| 	s := new(big.Int).Exp(pub.Y, k, pub.P) | ||||
| 	c2 = s.Mul(s, m) | ||||
| 	c2.Mod(c2, pub.P) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Decrypt takes two integers, resulting from an ElGamal encryption, and | ||||
| // returns the plaintext of the message. An error can result only if the | ||||
| // ciphertext is invalid. Users should keep in mind that this is a padding | ||||
| // oracle and thus, if exposed to an adaptive chosen ciphertext attack, can | ||||
| // be used to break the cryptosystem.  See ``Chosen Ciphertext Attacks | ||||
| // Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel | ||||
| // Bleichenbacher, Advances in Cryptology (Crypto '98), | ||||
| func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { | ||||
| 	s := new(big.Int).Exp(c1, priv.X, priv.P) | ||||
| 	s.ModInverse(s, priv.P) | ||||
| 	s.Mul(s, c2) | ||||
| 	s.Mod(s, priv.P) | ||||
| 	em := s.Bytes() | ||||
|  | ||||
| 	firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) | ||||
|  | ||||
| 	// The remainder of the plaintext must be a string of non-zero random | ||||
| 	// octets, followed by a 0, followed by the message. | ||||
| 	//   lookingForIndex: 1 iff we are still looking for the zero. | ||||
| 	//   index: the offset of the first zero byte. | ||||
| 	var lookingForIndex, index int | ||||
| 	lookingForIndex = 1 | ||||
|  | ||||
| 	for i := 1; i < len(em); i++ { | ||||
| 		equals0 := subtle.ConstantTimeByteEq(em[i], 0) | ||||
| 		index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) | ||||
| 		lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) | ||||
| 	} | ||||
|  | ||||
| 	if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { | ||||
| 		return nil, errors.New("elgamal: decryption error") | ||||
| 	} | ||||
| 	return em[index+1:], nil | ||||
| } | ||||
|  | ||||
| // nonZeroRandomBytes fills the given slice with non-zero random octets. | ||||
| func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { | ||||
| 	_, err = io.ReadFull(rand, s) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		for s[i] == 0 { | ||||
| 			_, err = io.ReadFull(rand, s[i:i+1]) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										72
									
								
								vendor/github.com/keybase/go-crypto/openpgp/errors/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/keybase/go-crypto/openpgp/errors/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| // 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. | ||||
|  | ||||
| // Package errors contains common error types for the OpenPGP packages. | ||||
| package errors // import "github.com/keybase/go-crypto/openpgp/errors" | ||||
|  | ||||
| import ( | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // A StructuralError is returned when OpenPGP data is found to be syntactically | ||||
| // invalid. | ||||
| type StructuralError string | ||||
|  | ||||
| func (s StructuralError) Error() string { | ||||
| 	return "openpgp: invalid data: " + string(s) | ||||
| } | ||||
|  | ||||
| // UnsupportedError indicates that, although the OpenPGP data is valid, it | ||||
| // makes use of currently unimplemented features. | ||||
| type UnsupportedError string | ||||
|  | ||||
| func (s UnsupportedError) Error() string { | ||||
| 	return "openpgp: unsupported feature: " + string(s) | ||||
| } | ||||
|  | ||||
| // InvalidArgumentError indicates that the caller is in error and passed an | ||||
| // incorrect value. | ||||
| type InvalidArgumentError string | ||||
|  | ||||
| func (i InvalidArgumentError) Error() string { | ||||
| 	return "openpgp: invalid argument: " + string(i) | ||||
| } | ||||
|  | ||||
| // SignatureError indicates that a syntactically valid signature failed to | ||||
| // validate. | ||||
| type SignatureError string | ||||
|  | ||||
| func (b SignatureError) Error() string { | ||||
| 	return "openpgp: invalid signature: " + string(b) | ||||
| } | ||||
|  | ||||
| type keyIncorrectError int | ||||
|  | ||||
| func (ki keyIncorrectError) Error() string { | ||||
| 	return "openpgp: incorrect key" | ||||
| } | ||||
|  | ||||
| var ErrKeyIncorrect error = keyIncorrectError(0) | ||||
|  | ||||
| type unknownIssuerError int | ||||
|  | ||||
| func (unknownIssuerError) Error() string { | ||||
| 	return "openpgp: signature made by unknown entity" | ||||
| } | ||||
|  | ||||
| var ErrUnknownIssuer error = unknownIssuerError(0) | ||||
|  | ||||
| type keyRevokedError int | ||||
|  | ||||
| func (keyRevokedError) Error() string { | ||||
| 	return "openpgp: signature made by revoked key" | ||||
| } | ||||
|  | ||||
| var ErrKeyRevoked error = keyRevokedError(0) | ||||
|  | ||||
| type UnknownPacketTypeError uint8 | ||||
|  | ||||
| func (upte UnknownPacketTypeError) Error() string { | ||||
| 	return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) | ||||
| } | ||||
							
								
								
									
										902
									
								
								vendor/github.com/keybase/go-crypto/openpgp/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										902
									
								
								vendor/github.com/keybase/go-crypto/openpgp/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,902 @@ | ||||
| // Copyright 2011 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package openpgp | ||||
|  | ||||
| import ( | ||||
| 	"crypto/hmac" | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/armor" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/packet" | ||||
| 	"github.com/keybase/go-crypto/rsa" | ||||
| ) | ||||
|  | ||||
| // PublicKeyType is the armor type for a PGP public key. | ||||
| var PublicKeyType = "PGP PUBLIC KEY BLOCK" | ||||
|  | ||||
| // PrivateKeyType is the armor type for a PGP private key. | ||||
| var PrivateKeyType = "PGP PRIVATE KEY BLOCK" | ||||
|  | ||||
| // An Entity represents the components of an OpenPGP key: a primary public key | ||||
| // (which must be a signing key), one or more identities claimed by that key, | ||||
| // and zero or more subkeys, which may be encryption keys. | ||||
| type Entity struct { | ||||
| 	PrimaryKey  *packet.PublicKey | ||||
| 	PrivateKey  *packet.PrivateKey | ||||
| 	Identities  map[string]*Identity // indexed by Identity.Name | ||||
| 	Revocations []*packet.Signature | ||||
| 	// Revocations that are signed by designated revokers. Reading keys | ||||
| 	// will not verify these revocations, because it won't have access to | ||||
| 	// issuers' public keys, API consumers should do this instead (or | ||||
| 	// not, and just assume that the key is probably revoked). | ||||
| 	UnverifiedRevocations []*packet.Signature | ||||
| 	Subkeys               []Subkey | ||||
| 	BadSubkeys            []BadSubkey | ||||
| } | ||||
|  | ||||
| // An Identity represents an identity claimed by an Entity and zero or more | ||||
| // assertions by other entities about that claim. | ||||
| type Identity struct { | ||||
| 	Name          string // by convention, has the form "Full Name (comment) <email@example.com>" | ||||
| 	UserId        *packet.UserId | ||||
| 	SelfSignature *packet.Signature | ||||
| 	Signatures    []*packet.Signature | ||||
| 	Revocation    *packet.Signature | ||||
| } | ||||
|  | ||||
| // A Subkey is an additional public key in an Entity. Subkeys can be used for | ||||
| // encryption. | ||||
| type Subkey struct { | ||||
| 	PublicKey  *packet.PublicKey | ||||
| 	PrivateKey *packet.PrivateKey | ||||
| 	Sig        *packet.Signature | ||||
| 	Revocation *packet.Signature | ||||
| } | ||||
|  | ||||
| // BadSubkey is one that failed reconstruction, but we'll keep it around for | ||||
| // informational purposes. | ||||
| type BadSubkey struct { | ||||
| 	Subkey | ||||
| 	Err error | ||||
| } | ||||
|  | ||||
| // A Key identifies a specific public key in an Entity. This is either the | ||||
| // Entity's primary key or a subkey. | ||||
| type Key struct { | ||||
| 	Entity        *Entity | ||||
| 	PublicKey     *packet.PublicKey | ||||
| 	PrivateKey    *packet.PrivateKey | ||||
| 	SelfSignature *packet.Signature | ||||
| 	KeyFlags      packet.KeyFlagBits | ||||
| } | ||||
|  | ||||
| // A KeyRing provides access to public and private keys. | ||||
| type KeyRing interface { | ||||
|  | ||||
| 	// KeysById returns the set of keys that have the given key id. | ||||
| 	// fp can be optionally supplied, which is the full key fingerprint. | ||||
| 	// If it's provided, then it must match. This comes up in the case | ||||
| 	// of GPG subpacket 33. | ||||
| 	KeysById(id uint64, fp []byte) []Key | ||||
|  | ||||
| 	// KeysByIdAndUsage returns the set of keys with the given id | ||||
| 	// that also meet the key usage given by requiredUsage. | ||||
| 	// The requiredUsage is expressed as the bitwise-OR of | ||||
| 	// packet.KeyFlag* values. | ||||
| 	// fp can be optionally supplied, which is the full key fingerprint. | ||||
| 	// If it's provided, then it must match. This comes up in the case | ||||
| 	// of GPG subpacket 33. | ||||
| 	KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) []Key | ||||
|  | ||||
| 	// DecryptionKeys returns all private keys that are valid for | ||||
| 	// decryption. | ||||
| 	DecryptionKeys() []Key | ||||
| } | ||||
|  | ||||
| // primaryIdentity returns the Identity marked as primary or the first identity | ||||
| // if none are so marked. | ||||
| func (e *Entity) primaryIdentity() *Identity { | ||||
| 	var firstIdentity *Identity | ||||
| 	for _, ident := range e.Identities { | ||||
| 		if firstIdentity == nil { | ||||
| 			firstIdentity = ident | ||||
| 		} | ||||
| 		if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | ||||
| 			return ident | ||||
| 		} | ||||
| 	} | ||||
| 	return firstIdentity | ||||
| } | ||||
|  | ||||
| // encryptionKey returns the best candidate Key for encrypting a message to the | ||||
| // given Entity. | ||||
| func (e *Entity) encryptionKey(now time.Time) (Key, bool) { | ||||
| 	candidateSubkey := -1 | ||||
|  | ||||
| 	// Iterate the keys to find the newest key | ||||
| 	var maxTime time.Time | ||||
| 	for i, subkey := range e.Subkeys { | ||||
|  | ||||
| 		// NOTE(maxtaco) | ||||
| 		// If there is a Flags subpacket, then we have to follow it, and only | ||||
| 		// use keys that are marked for Encryption of Communication.  If there | ||||
| 		// isn't a Flags subpacket, and this is an Encrypt-Only key (right now only ElGamal | ||||
| 		// suffices), then we implicitly use it. The check for primary below is a little | ||||
| 		// more open-ended, but for now, let's be strict and potentially open up | ||||
| 		// if we see bugs in the wild. | ||||
| 		// | ||||
| 		// One more note: old DSA/ElGamal keys tend not to have the Flags subpacket, | ||||
| 		// so this sort of thing is pretty important for encrypting to older keys. | ||||
| 		// | ||||
| 		if ((subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications) || | ||||
| 			(!subkey.Sig.FlagsValid && subkey.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal)) && | ||||
| 			subkey.PublicKey.PubKeyAlgo.CanEncrypt() && | ||||
| 			!subkey.Sig.KeyExpired(now) && | ||||
| 			subkey.Revocation == nil && | ||||
| 			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { | ||||
| 			candidateSubkey = i | ||||
| 			maxTime = subkey.Sig.CreationTime | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if candidateSubkey != -1 { | ||||
| 		subkey := e.Subkeys[candidateSubkey] | ||||
| 		return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, true | ||||
| 	} | ||||
|  | ||||
| 	// If we don't have any candidate subkeys for encryption and | ||||
| 	// the primary key doesn't have any usage metadata then we | ||||
| 	// assume that the primary key is ok. Or, if the primary key is | ||||
| 	// marked as ok to encrypt to, then we can obviously use it. | ||||
| 	// | ||||
| 	// NOTE(maxtaco) - see note above, how this policy is a little too open-ended | ||||
| 	// for my liking, but leave it for now. | ||||
| 	i := e.primaryIdentity() | ||||
| 	if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications) && | ||||
| 		e.PrimaryKey.PubKeyAlgo.CanEncrypt() && | ||||
| 		!i.SelfSignature.KeyExpired(now) { | ||||
| 		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true | ||||
| 	} | ||||
|  | ||||
| 	// This Entity appears to be signing only. | ||||
| 	return Key{}, false | ||||
| } | ||||
|  | ||||
| // signingKey return the best candidate Key for signing a message with this | ||||
| // Entity. | ||||
| func (e *Entity) signingKey(now time.Time) (Key, bool) { | ||||
| 	candidateSubkey := -1 | ||||
|  | ||||
| 	for i, subkey := range e.Subkeys { | ||||
| 		if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) && | ||||
| 			subkey.PrivateKey.PrivateKey != nil && | ||||
| 			subkey.PublicKey.PubKeyAlgo.CanSign() && | ||||
| 			subkey.Revocation == nil && | ||||
| 			!subkey.Sig.KeyExpired(now) { | ||||
| 			candidateSubkey = i | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if candidateSubkey != -1 { | ||||
| 		subkey := e.Subkeys[candidateSubkey] | ||||
| 		return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, true | ||||
| 	} | ||||
|  | ||||
| 	// If we have no candidate subkey then we assume that it's ok to sign | ||||
| 	// with the primary key. | ||||
| 	i := e.primaryIdentity() | ||||
| 	if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign) && | ||||
| 		e.PrimaryKey.PubKeyAlgo.CanSign() && | ||||
| 		!i.SelfSignature.KeyExpired(now) && | ||||
| 		e.PrivateKey.PrivateKey != nil { | ||||
| 		return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true | ||||
| 	} | ||||
|  | ||||
| 	return Key{}, false | ||||
| } | ||||
|  | ||||
| // An EntityList contains one or more Entities. | ||||
| type EntityList []*Entity | ||||
|  | ||||
| func keyMatchesIdAndFingerprint(key *packet.PublicKey, id uint64, fp []byte) bool { | ||||
| 	if key.KeyId != id { | ||||
| 		return false | ||||
| 	} | ||||
| 	if fp == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return hmac.Equal(fp, key.Fingerprint[:]) | ||||
| } | ||||
|  | ||||
| // KeysById returns the set of keys that have the given key id. | ||||
| // fp can be optionally supplied, which is the full key fingerprint. | ||||
| // If it's provided, then it must match. This comes up in the case | ||||
| // of GPG subpacket 33. | ||||
| func (el EntityList) KeysById(id uint64, fp []byte) (keys []Key) { | ||||
| 	for _, e := range el { | ||||
| 		if keyMatchesIdAndFingerprint(e.PrimaryKey, id, fp) { | ||||
| 			var selfSig *packet.Signature | ||||
| 			for _, ident := range e.Identities { | ||||
| 				if selfSig == nil { | ||||
| 					selfSig = ident.SelfSignature | ||||
| 				} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { | ||||
| 					selfSig = ident.SelfSignature | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			var keyFlags packet.KeyFlagBits | ||||
| 			for _, ident := range e.Identities { | ||||
| 				keyFlags.Merge(ident.SelfSignature.GetKeyFlags()) | ||||
| 			} | ||||
|  | ||||
| 			keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, keyFlags}) | ||||
| 		} | ||||
|  | ||||
| 		for _, subKey := range e.Subkeys { | ||||
| 			if keyMatchesIdAndFingerprint(subKey.PublicKey, id, fp) { | ||||
|  | ||||
| 				// If there's both a a revocation and a sig, then take the | ||||
| 				// revocation. Otherwise, we can proceed with the sig. | ||||
| 				sig := subKey.Revocation | ||||
| 				if sig == nil { | ||||
| 					sig = subKey.Sig | ||||
| 				} | ||||
|  | ||||
| 				keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, sig, sig.GetKeyFlags()}) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // KeysByIdAndUsage returns the set of keys with the given id that also meet | ||||
| // the key usage given by requiredUsage.  The requiredUsage is expressed as | ||||
| // the bitwise-OR of packet.KeyFlag* values. | ||||
| // fp can be optionally supplied, which is the full key fingerprint. | ||||
| // If it's provided, then it must match. This comes up in the case | ||||
| // of GPG subpacket 33. | ||||
| func (el EntityList) KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) (keys []Key) { | ||||
| 	for _, key := range el.KeysById(id, fp) { | ||||
| 		if len(key.Entity.Revocations) > 0 { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if key.SelfSignature.RevocationReason != nil { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if requiredUsage != 0 { | ||||
| 			var usage byte | ||||
|  | ||||
| 			switch { | ||||
| 			case key.KeyFlags.Valid: | ||||
| 				usage = key.KeyFlags.BitField | ||||
|  | ||||
| 			case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal: | ||||
| 				// We also need to handle the case where, although the sig's | ||||
| 				// flags aren't valid, the key can is implicitly usable for | ||||
| 				// encryption by virtue of being ElGamal. See also the comment | ||||
| 				// in encryptionKey() above. | ||||
| 				usage |= packet.KeyFlagEncryptCommunications | ||||
| 				usage |= packet.KeyFlagEncryptStorage | ||||
|  | ||||
| 			case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoDSA || | ||||
| 				key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoECDSA || | ||||
| 				key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA: | ||||
| 				usage |= packet.KeyFlagSign | ||||
|  | ||||
| 			// For a primary RSA key without any key flags, be as permissiable | ||||
| 			// as possible. | ||||
| 			case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoRSA && | ||||
| 				keyMatchesIdAndFingerprint(key.Entity.PrimaryKey, id, fp): | ||||
| 				usage = (packet.KeyFlagCertify | packet.KeyFlagSign | | ||||
| 					packet.KeyFlagEncryptCommunications | packet.KeyFlagEncryptStorage) | ||||
| 			} | ||||
|  | ||||
| 			if usage&requiredUsage != requiredUsage { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		keys = append(keys, key) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // DecryptionKeys returns all private keys that are valid for decryption. | ||||
| func (el EntityList) DecryptionKeys() (keys []Key) { | ||||
| 	for _, e := range el { | ||||
| 		for _, subKey := range e.Subkeys { | ||||
| 			if subKey.PrivateKey != nil && subKey.PrivateKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) { | ||||
| 				keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Sig.GetKeyFlags()}) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. | ||||
| func ReadArmoredKeyRing(r io.Reader) (EntityList, error) { | ||||
| 	block, err := armor.Decode(r) | ||||
| 	if err == io.EOF { | ||||
| 		return nil, errors.InvalidArgumentError("no armored data found") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if block.Type != PublicKeyType && block.Type != PrivateKeyType { | ||||
| 		return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type) | ||||
| 	} | ||||
|  | ||||
| 	return ReadKeyRing(block.Body) | ||||
| } | ||||
|  | ||||
| // ReadKeyRing reads one or more public/private keys. Unsupported keys are | ||||
| // ignored as long as at least a single valid key is found. | ||||
| func ReadKeyRing(r io.Reader) (el EntityList, err error) { | ||||
| 	packets := packet.NewReader(r) | ||||
| 	var lastUnsupportedError error | ||||
|  | ||||
| 	for { | ||||
| 		var e *Entity | ||||
| 		e, err = ReadEntity(packets) | ||||
| 		if err != nil { | ||||
| 			// TODO: warn about skipped unsupported/unreadable keys | ||||
| 			if _, ok := err.(errors.UnsupportedError); ok { | ||||
| 				lastUnsupportedError = err | ||||
| 				err = readToNextPublicKey(packets) | ||||
| 			} else if _, ok := err.(errors.StructuralError); ok { | ||||
| 				// Skip unreadable, badly-formatted keys | ||||
| 				lastUnsupportedError = err | ||||
| 				err = readToNextPublicKey(packets) | ||||
| 			} | ||||
| 			if err == io.EOF { | ||||
| 				err = nil | ||||
| 				break | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				el = nil | ||||
| 				break | ||||
| 			} | ||||
| 		} else { | ||||
| 			el = append(el, e) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(el) == 0 && err == nil { | ||||
| 		err = lastUnsupportedError | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // readToNextPublicKey reads packets until the start of the entity and leaves | ||||
| // the first packet of the new entity in the Reader. | ||||
| func readToNextPublicKey(packets *packet.Reader) (err error) { | ||||
| 	var p packet.Packet | ||||
| 	for { | ||||
| 		p, err = packets.Next() | ||||
| 		if err == io.EOF { | ||||
| 			return | ||||
| 		} else if err != nil { | ||||
| 			if _, ok := err.(errors.UnsupportedError); ok { | ||||
| 				err = nil | ||||
| 				continue | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey { | ||||
| 			packets.Unread(p) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // ReadEntity reads an entity (public key, identities, subkeys etc) from the | ||||
| // given Reader. | ||||
| func ReadEntity(packets *packet.Reader) (*Entity, error) { | ||||
| 	e := new(Entity) | ||||
| 	e.Identities = make(map[string]*Identity) | ||||
|  | ||||
| 	p, err := packets.Next() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var ok bool | ||||
| 	if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { | ||||
| 		if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { | ||||
| 			packets.Unread(p) | ||||
| 			return nil, errors.StructuralError("first packet was not a public/private key") | ||||
| 		} else { | ||||
| 			e.PrimaryKey = &e.PrivateKey.PublicKey | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !e.PrimaryKey.PubKeyAlgo.CanSign() { | ||||
| 		return nil, errors.StructuralError("primary key cannot be used for signatures") | ||||
| 	} | ||||
|  | ||||
| 	var current *Identity | ||||
| 	var revocations []*packet.Signature | ||||
|  | ||||
| 	designatedRevokers := make(map[uint64]bool) | ||||
| EachPacket: | ||||
| 	for { | ||||
| 		p, err := packets.Next() | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} else if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		switch pkt := p.(type) { | ||||
| 		case *packet.UserId: | ||||
|  | ||||
| 			// Make a new Identity object, that we might wind up throwing away. | ||||
| 			// We'll only add it if we get a valid self-signature over this | ||||
| 			// userID. | ||||
| 			current = new(Identity) | ||||
| 			current.Name = pkt.Id | ||||
| 			current.UserId = pkt | ||||
| 		case *packet.Signature: | ||||
| 			if pkt.SigType == packet.SigTypeKeyRevocation { | ||||
| 				// These revocations won't revoke UIDs (see | ||||
| 				// SigTypeIdentityRevocation). Handle these first, | ||||
| 				// because key might have revocation coming from | ||||
| 				// another key (designated revoke). | ||||
| 				revocations = append(revocations, pkt) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			// These are signatures by other people on this key. Let's just ignore them | ||||
| 			// from the beginning, since they shouldn't affect our key decoding one way | ||||
| 			// or the other. | ||||
| 			if pkt.IssuerKeyId != nil && *pkt.IssuerKeyId != e.PrimaryKey.KeyId { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			// If this is a signature made by the keyholder, and the signature has stubbed out | ||||
| 			// critical packets, then *now* we need to bail out. | ||||
| 			if e := pkt.StubbedOutCriticalError; e != nil { | ||||
| 				return nil, e | ||||
| 			} | ||||
|  | ||||
| 			// Next handle the case of a self-signature. According to RFC8440, | ||||
| 			// Section 5.2.3.3, if there are several self-signatures, | ||||
| 			// we should take the newer one.  If they were both created | ||||
| 			// at the same time, but one of them has keyflags specified and the | ||||
| 			// other doesn't, keep the one with the keyflags. We have actually | ||||
| 			// seen this in the wild (see the 'Yield' test in read_test.go). | ||||
| 			// If there is a tie, and both have the same value for FlagsValid, | ||||
| 			// then "last writer wins." | ||||
| 			// | ||||
| 			// HOWEVER! We have seen yet more keys in the wild (see the 'Spiros' | ||||
| 			// test in read_test.go), in which the later self-signature is a bunch | ||||
| 			// of junk, and doesn't even specify key flags. Does it really make | ||||
| 			// sense to overwrite reasonable key flags with the empty set? I'm not | ||||
| 			// sure what that would be trying to achieve, and plus GPG seems to be | ||||
| 			// ok with this situation, and ignores the later (empty) keyflag set. | ||||
| 			// So further tighten our overwrite rules, and only allow the later | ||||
| 			// signature to overwrite the earlier signature if so doing won't | ||||
| 			// trash the key flags. | ||||
| 			if current != nil && | ||||
| 				(current.SelfSignature == nil || | ||||
| 					(!pkt.CreationTime.Before(current.SelfSignature.CreationTime) && | ||||
| 						(pkt.FlagsValid || !current.SelfSignature.FlagsValid))) && | ||||
| 				(pkt.SigType == packet.SigTypePositiveCert || pkt.SigType == packet.SigTypeGenericCert) && | ||||
| 				pkt.IssuerKeyId != nil && | ||||
| 				*pkt.IssuerKeyId == e.PrimaryKey.KeyId { | ||||
|  | ||||
| 				if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil { | ||||
|  | ||||
| 					current.SelfSignature = pkt | ||||
|  | ||||
| 					// NOTE(maxtaco) 2016.01.11 | ||||
| 					// Only register an identity once we've gotten a valid self-signature. | ||||
| 					// It's possible therefore for us to throw away `current` in the case | ||||
| 					// no valid self-signatures were found. That's OK as long as there are | ||||
| 					// other identies that make sense. | ||||
| 					// | ||||
| 					// NOTE! We might later see a revocation for this very same UID, and it | ||||
| 					// won't be undone. We've preserved this feature from the original | ||||
| 					// Google OpenPGP we forked from. | ||||
| 					e.Identities[current.Name] = current | ||||
| 				} else { | ||||
| 					// We really should warn that there was a failure here. Not raise an error | ||||
| 					// since this really shouldn't be a fail-stop error. | ||||
| 				} | ||||
| 			} else if current != nil && pkt.SigType == packet.SigTypeIdentityRevocation { | ||||
| 				if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil { | ||||
| 					// Note: we are not removing the identity from | ||||
| 					// e.Identities. Caller can always filter by Revocation | ||||
| 					// field to ignore revoked identities. | ||||
| 					current.Revocation = pkt | ||||
| 				} | ||||
| 			} else if pkt.SigType == packet.SigTypeDirectSignature { | ||||
| 				if err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, pkt); err == nil { | ||||
| 					if desig := pkt.DesignatedRevoker; desig != nil { | ||||
| 						// If it's a designated revoker signature, take last 8 octects | ||||
| 						// of fingerprint as Key ID and save it to designatedRevokers | ||||
| 						// map. We consult this map later to see if a foreign | ||||
| 						// revocation should be added to UnverifiedRevocations. | ||||
| 						keyID := binary.BigEndian.Uint64(desig.Fingerprint[len(desig.Fingerprint)-8:]) | ||||
| 						designatedRevokers[keyID] = true | ||||
| 					} | ||||
| 				} | ||||
| 			} else if current == nil { | ||||
| 				// NOTE(maxtaco) | ||||
| 				// | ||||
| 				// See https://github.com/keybase/client/issues/2666 | ||||
| 				// | ||||
| 				// There might have been a user attribute picture before this signature, | ||||
| 				// in which case this is still a valid PGP key. In the future we might | ||||
| 				// not ignore user attributes (like picture). But either way, it doesn't | ||||
| 				// make sense to bail out here. Keep looking for other valid signatures. | ||||
| 				// | ||||
| 				// Used to be: | ||||
| 				//    return nil, errors.StructuralError("signature packet found before user id packet") | ||||
| 			} else { | ||||
| 				current.Signatures = append(current.Signatures, pkt) | ||||
| 			} | ||||
| 		case *packet.PrivateKey: | ||||
| 			if pkt.IsSubkey == false { | ||||
| 				packets.Unread(p) | ||||
| 				break EachPacket | ||||
| 			} | ||||
| 			err = addSubkey(e, packets, &pkt.PublicKey, pkt) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		case *packet.PublicKey: | ||||
| 			if pkt.IsSubkey == false { | ||||
| 				packets.Unread(p) | ||||
| 				break EachPacket | ||||
| 			} | ||||
| 			err = addSubkey(e, packets, pkt, nil) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		default: | ||||
| 			// we ignore unknown packets | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(e.Identities) == 0 { | ||||
| 		return nil, errors.StructuralError("entity without any identities") | ||||
| 	} | ||||
|  | ||||
| 	for _, revocation := range revocations { | ||||
| 		if revocation.IssuerKeyId == nil || *revocation.IssuerKeyId == e.PrimaryKey.KeyId { | ||||
| 			// Key revokes itself, something that we can verify. | ||||
| 			err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, revocation) | ||||
| 			if err == nil { | ||||
| 				e.Revocations = append(e.Revocations, revocation) | ||||
| 			} else { | ||||
| 				return nil, errors.StructuralError("revocation signature signed by alternate key") | ||||
| 			} | ||||
| 		} else if revocation.IssuerKeyId != nil { | ||||
| 			if _, ok := designatedRevokers[*revocation.IssuerKeyId]; ok { | ||||
| 				// Revocation is done by certified designated revoker, | ||||
| 				// but we can't verify the revocation. | ||||
| 				e.UnverifiedRevocations = append(e.UnverifiedRevocations, revocation) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return e, nil | ||||
| } | ||||
|  | ||||
| func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { | ||||
| 	var subKey Subkey | ||||
| 	subKey.PublicKey = pub | ||||
| 	subKey.PrivateKey = priv | ||||
| 	var lastErr error | ||||
| 	for { | ||||
| 		p, err := packets.Next() | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return errors.StructuralError("subkey signature invalid: " + err.Error()) | ||||
| 		} | ||||
| 		sig, ok := p.(*packet.Signature) | ||||
| 		if !ok { | ||||
| 			// Hit a non-signature packet, so assume we're up to the next key | ||||
| 			packets.Unread(p) | ||||
| 			break | ||||
| 		} | ||||
| 		if st := sig.SigType; st != packet.SigTypeSubkeyBinding && st != packet.SigTypeSubkeyRevocation { | ||||
|  | ||||
| 			// Note(maxtaco): | ||||
| 			// We used to error out here, but instead, let's fast-forward past | ||||
| 			// packets that are in the wrong place (like misplaced 0x13 signatures) | ||||
| 			// until we get to one that works.  For a test case, | ||||
| 			// see TestWithBadSubkeySignaturePackets. | ||||
|  | ||||
| 			continue | ||||
| 		} | ||||
| 		err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig) | ||||
| 		if err != nil { | ||||
| 			// Non valid signature, so again, no need to abandon all hope, just continue; | ||||
| 			// make a note of the error we hit. | ||||
| 			lastErr = errors.StructuralError("subkey signature invalid: " + err.Error()) | ||||
| 			continue | ||||
| 		} | ||||
| 		switch sig.SigType { | ||||
| 		case packet.SigTypeSubkeyBinding: | ||||
| 			// Does the "new" sig set expiration to later date than | ||||
| 			// "previous" sig? | ||||
| 			if subKey.Sig == nil || subKey.Sig.ExpiresBeforeOther(sig) { | ||||
| 				subKey.Sig = sig | ||||
| 			} | ||||
| 		case packet.SigTypeSubkeyRevocation: | ||||
| 			// First writer wins | ||||
| 			if subKey.Revocation == nil { | ||||
| 				subKey.Revocation = sig | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if subKey.Sig != nil { | ||||
| 		e.Subkeys = append(e.Subkeys, subKey) | ||||
| 	} else { | ||||
| 		if lastErr == nil { | ||||
| 			lastErr = errors.StructuralError("Subkey wasn't signed; expected a 'binding' signature") | ||||
| 		} | ||||
| 		e.BadSubkeys = append(e.BadSubkeys, BadSubkey{Subkey: subKey, Err: lastErr}) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| const defaultRSAKeyBits = 2048 | ||||
|  | ||||
| // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a | ||||
| // single identity composed of the given full name, comment and email, any of | ||||
| // which may be empty but must not contain any of "()<>\x00". | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { | ||||
| 	currentTime := config.Now() | ||||
|  | ||||
| 	bits := defaultRSAKeyBits | ||||
| 	if config != nil && config.RSABits != 0 { | ||||
| 		bits = config.RSABits | ||||
| 	} | ||||
|  | ||||
| 	uid := packet.NewUserId(name, comment, email) | ||||
| 	if uid == nil { | ||||
| 		return nil, errors.InvalidArgumentError("user id field contained invalid characters") | ||||
| 	} | ||||
| 	signingPriv, err := rsa.GenerateKey(config.Random(), bits) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	encryptingPriv, err := rsa.GenerateKey(config.Random(), bits) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	e := &Entity{ | ||||
| 		PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey), | ||||
| 		PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv), | ||||
| 		Identities: make(map[string]*Identity), | ||||
| 	} | ||||
| 	isPrimaryId := true | ||||
| 	e.Identities[uid.Id] = &Identity{ | ||||
| 		Name:   uid.Name, | ||||
| 		UserId: uid, | ||||
| 		SelfSignature: &packet.Signature{ | ||||
| 			CreationTime: currentTime, | ||||
| 			SigType:      packet.SigTypePositiveCert, | ||||
| 			PubKeyAlgo:   packet.PubKeyAlgoRSA, | ||||
| 			Hash:         config.Hash(), | ||||
| 			IsPrimaryId:  &isPrimaryId, | ||||
| 			FlagsValid:   true, | ||||
| 			FlagSign:     true, | ||||
| 			FlagCertify:  true, | ||||
| 			IssuerKeyId:  &e.PrimaryKey.KeyId, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	e.Subkeys = make([]Subkey, 1) | ||||
| 	e.Subkeys[0] = Subkey{ | ||||
| 		PublicKey:  packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), | ||||
| 		PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv), | ||||
| 		Sig: &packet.Signature{ | ||||
| 			CreationTime:              currentTime, | ||||
| 			SigType:                   packet.SigTypeSubkeyBinding, | ||||
| 			PubKeyAlgo:                packet.PubKeyAlgoRSA, | ||||
| 			Hash:                      config.Hash(), | ||||
| 			FlagsValid:                true, | ||||
| 			FlagEncryptStorage:        true, | ||||
| 			FlagEncryptCommunications: true, | ||||
| 			IssuerKeyId:               &e.PrimaryKey.KeyId, | ||||
| 		}, | ||||
| 	} | ||||
| 	e.Subkeys[0].PublicKey.IsSubkey = true | ||||
| 	e.Subkeys[0].PrivateKey.IsSubkey = true | ||||
|  | ||||
| 	return e, nil | ||||
| } | ||||
|  | ||||
| // SerializePrivate serializes an Entity, including private key material, to | ||||
| // the given Writer. For now, it must only be used on an Entity returned from | ||||
| // NewEntity. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { | ||||
| 	err = e.PrivateKey.Serialize(w) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, ident := range e.Identities { | ||||
| 		err = ident.UserId.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if e.PrivateKey.PrivateKey != nil { | ||||
| 			err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		err = ident.SelfSignature.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	for _, subkey := range e.Subkeys { | ||||
| 		err = subkey.PrivateKey.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		// Workaround shortcoming of SignKey(), which doesn't work to reverse-sign | ||||
| 		// sub-signing keys. So if requested, just reuse the signatures already | ||||
| 		// available to us (if we read this key from a keyring). | ||||
| 		if e.PrivateKey.PrivateKey != nil && !config.ReuseSignatures() { | ||||
| 			err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if subkey.Revocation != nil { | ||||
| 			err = subkey.Revocation.Serialize(w) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		err = subkey.Sig.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Serialize writes the public part of the given Entity to w. (No private | ||||
| // key material will be output). | ||||
| func (e *Entity) Serialize(w io.Writer) error { | ||||
| 	err := e.PrimaryKey.Serialize(w) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, ident := range e.Identities { | ||||
| 		err = ident.UserId.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		err = ident.SelfSignature.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		for _, sig := range ident.Signatures { | ||||
| 			err = sig.Serialize(w) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	for _, subkey := range e.Subkeys { | ||||
| 		err = subkey.PublicKey.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if subkey.Revocation != nil { | ||||
| 			err = subkey.Revocation.Serialize(w) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		err = subkey.Sig.Serialize(w) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // SignIdentity adds a signature to e, from signer, attesting that identity is | ||||
| // associated with e. The provided identity must already be an element of | ||||
| // e.Identities and the private key of signer must have been decrypted if | ||||
| // necessary. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error { | ||||
| 	if signer.PrivateKey == nil { | ||||
| 		return errors.InvalidArgumentError("signing Entity must have a private key") | ||||
| 	} | ||||
| 	if signer.PrivateKey.Encrypted { | ||||
| 		return errors.InvalidArgumentError("signing Entity's private key must be decrypted") | ||||
| 	} | ||||
| 	ident, ok := e.Identities[identity] | ||||
| 	if !ok { | ||||
| 		return errors.InvalidArgumentError("given identity string not found in Entity") | ||||
| 	} | ||||
|  | ||||
| 	sig := &packet.Signature{ | ||||
| 		SigType:      packet.SigTypeGenericCert, | ||||
| 		PubKeyAlgo:   signer.PrivateKey.PubKeyAlgo, | ||||
| 		Hash:         config.Hash(), | ||||
| 		CreationTime: config.Now(), | ||||
| 		IssuerKeyId:  &signer.PrivateKey.KeyId, | ||||
| 	} | ||||
| 	if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	ident.Signatures = append(ident.Signatures, sig) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // CopySubkeyRevocations copies subkey revocations from the src Entity over | ||||
| // to the receiver entity. We need this because `gpg --export-secret-key` does | ||||
| // not appear to output subkey revocations.  In this case we need to manually | ||||
| // merge with the output of `gpg --export`. | ||||
| func (e *Entity) CopySubkeyRevocations(src *Entity) { | ||||
| 	m := make(map[[20]byte]*packet.Signature) | ||||
| 	for _, subkey := range src.Subkeys { | ||||
| 		if subkey.Revocation != nil { | ||||
| 			m[subkey.PublicKey.Fingerprint] = subkey.Revocation | ||||
| 		} | ||||
| 	} | ||||
| 	for i, subkey := range e.Subkeys { | ||||
| 		if r := m[subkey.PublicKey.Fingerprint]; r != nil { | ||||
| 			e.Subkeys[i].Revocation = r | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CheckDesignatedRevokers will try to confirm any of designated | ||||
| // revocation of entity. For this function to work, revocation | ||||
| // issuer's key should be found in keyring. First successfully | ||||
| // verified designated revocation is returned along with the key that | ||||
| // verified it. | ||||
| func FindVerifiedDesignatedRevoke(keyring KeyRing, entity *Entity) (*packet.Signature, *Key) { | ||||
| 	for _, sig := range entity.UnverifiedRevocations { | ||||
| 		if sig.IssuerKeyId == nil { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		issuerKeyId := *sig.IssuerKeyId | ||||
| 		issuerFingerprint := sig.IssuerFingerprint | ||||
| 		keys := keyring.KeysByIdUsage(issuerKeyId, issuerFingerprint, packet.KeyFlagSign) | ||||
| 		if len(keys) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, key := range keys { | ||||
| 			err := key.PublicKey.VerifyRevocationSignature(entity.PrimaryKey, sig) | ||||
| 			if err == nil { | ||||
| 				return sig, &key | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil, nil | ||||
| } | ||||
							
								
								
									
										124
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/compressed.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/compressed.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| // 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" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
| } | ||||
							
								
								
									
										98
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| // 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" | ||||
| 	"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 | ||||
| 	// ReuseSignatures tells us to reuse existing Signatures | ||||
| 	// on serialized output. | ||||
| 	ReuseSignaturesOnSerialize bool | ||||
| } | ||||
|  | ||||
| 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() | ||||
| } | ||||
|  | ||||
| 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) ReuseSignatures() bool { | ||||
| 	return c != nil && c.ReuseSignaturesOnSerialize | ||||
| } | ||||
							
								
								
									
										104
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/ecdh.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| package packet | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/s2k" | ||||
| ) | ||||
|  | ||||
| // ECDHKdfParams generates KDF parameters sequence for given | ||||
| // PublicKey. See https://tools.ietf.org/html/rfc6637#section-8 | ||||
| func ECDHKdfParams(pub *PublicKey) []byte { | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	oid := pub.ec.oid | ||||
| 	buf.WriteByte(byte(len(oid))) | ||||
| 	buf.Write(oid) | ||||
| 	buf.WriteByte(18) // ECDH TYPE | ||||
| 	pub.ecdh.serialize(buf) | ||||
| 	buf.WriteString("Anonymous Sender    ") | ||||
| 	buf.Write(pub.Fingerprint[:]) | ||||
| 	return buf.Bytes() | ||||
| } | ||||
|  | ||||
| func decryptKeyECDH(priv *PrivateKey, X, Y *big.Int, C []byte) (out []byte, err error) { | ||||
| 	ecdhpriv, ok := priv.PrivateKey.(*ecdh.PrivateKey) | ||||
| 	if !ok { | ||||
| 		return nil, errors.InvalidArgumentError("bad internal ECDH key") | ||||
| 	} | ||||
|  | ||||
| 	Sx := ecdhpriv.DecryptShared(X, Y) | ||||
|  | ||||
| 	kdfParams := ECDHKdfParams(&priv.PublicKey) | ||||
| 	hash, ok := s2k.HashIdToHash(byte(priv.ecdh.KdfHash)) | ||||
| 	if !ok { | ||||
| 		return nil, errors.InvalidArgumentError("invalid hash id in private key") | ||||
| 	} | ||||
|  | ||||
| 	key := ecdhpriv.KDF(Sx, kdfParams, hash) | ||||
| 	keySize := CipherFunction(priv.ecdh.KdfAlgo).KeySize() | ||||
|  | ||||
| 	decrypted, err := ecdh.AESKeyUnwrap(key[:keySize], C) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// We have to "read ahead" to discover real length of the | ||||
| 	// encryption key and properly unpad buffer. | ||||
| 	cipherFunc := CipherFunction(decrypted[0]) | ||||
| 	// +3 bytes = 1-byte cipher id and checksum 2-byte checksum. | ||||
| 	out = ecdh.UnpadBuffer(decrypted, cipherFunc.KeySize()+3) | ||||
| 	if out == nil { | ||||
| 		return nil, errors.InvalidArgumentError("invalid padding while ECDH") | ||||
| 	} | ||||
| 	return out, nil | ||||
| } | ||||
|  | ||||
| func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *PublicKey, keyBlock []byte) error { | ||||
| 	ecdhpub := pub.PublicKey.(*ecdh.PublicKey) | ||||
| 	kdfParams := ECDHKdfParams(pub) | ||||
|  | ||||
| 	hash, ok := s2k.HashIdToHash(byte(pub.ecdh.KdfHash)) | ||||
| 	if !ok { | ||||
| 		return errors.InvalidArgumentError("invalid hash id in private key") | ||||
| 	} | ||||
|  | ||||
| 	kdfKeySize := CipherFunction(pub.ecdh.KdfAlgo).KeySize() | ||||
| 	Vx, Vy, C, err := ecdhpub.Encrypt(rand, kdfParams, keyBlock, hash, kdfKeySize) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	mpis, mpiBitLen := ecdh.Marshal(ecdhpub.Curve, Vx, Vy) | ||||
|  | ||||
| 	packetLen := len(header) /* header length in bytes */ | ||||
| 	packetLen += 2 /* mpi length in bits */ + len(mpis) | ||||
| 	packetLen += 1 /* ciphertext size in bytes */ + len(C) | ||||
|  | ||||
| 	err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = w.Write(header[:]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = w.Write([]byte{byte(mpiBitLen >> 8), byte(mpiBitLen)}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = w.Write(mpis[:]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	w.Write([]byte{byte(len(C))}) | ||||
| 	w.Write(C[:]) | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										226
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/encrypted_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/encrypted_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| // 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" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/keybase/go-crypto/openpgp/elgamal" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/rsa" | ||||
| ) | ||||
|  | ||||
| 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 parsedMPI | ||||
| 	ecdh_C                       []byte | ||||
| } | ||||
|  | ||||
| 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.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err = readFull(r, buf[:1]) // read C len (1 byte) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		e.ecdh_C = make([]byte, int(buf[0])) | ||||
| 		_, err = readFull(r, e.ecdh_C) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = consumeAll(r) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| 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 { | ||||
| 	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: | ||||
| 		b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes) | ||||
| 	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: | ||||
| 		// Note: Unmarshal checks if point is on the curve. | ||||
| 		c1, c2 := ecdh.Unmarshal(priv.PrivateKey.(*ecdh.PrivateKey).Curve, e.encryptedMPI1.bytes) | ||||
| 		if c1 == nil { | ||||
| 			return errors.InvalidArgumentError("failed to parse EC point for encryption key") | ||||
| 		} | ||||
| 		b, err = decryptKeyECDH(priv, c1, c2, e.ecdh_C) | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("cannot decrypted 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 = 2 + len(e.encryptedMPI1.bytes) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes) | ||||
| 	default: | ||||
| 		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) | ||||
| 	} | ||||
|  | ||||
| 	serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) | ||||
|  | ||||
| 	w.Write([]byte{encryptedKeyVersion}) | ||||
| 	binary.Write(w, binary.BigEndian, e.KeyId) | ||||
| 	w.Write([]byte{byte(e.Algo)}) | ||||
|  | ||||
| 	switch e.Algo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: | ||||
| 		writeMPIs(w, e.encryptedMPI1) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2) | ||||
| 	default: | ||||
| 		panic("internal error") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 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, keyBlock) | ||||
| 	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()) | ||||
| 	} | ||||
|  | ||||
| 	packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText) | ||||
|  | ||||
| 	err = serializeHeader(w, packetTypeEncryptedKey, packetLen) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = w.Write(header[:]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return writeMPI(w, 8*uint16(len(cipherText)), cipherText) | ||||
| } | ||||
|  | ||||
| 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 | ||||
| 	} | ||||
| 	err = writeBig(w, c1) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return writeBig(w, c2) | ||||
| } | ||||
							
								
								
									
										89
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/literal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/literal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| // 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 { | ||||
| 	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.IsBinary = buf[0] == '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 | ||||
| } | ||||
							
								
								
									
										143
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/ocfb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/ocfb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| // 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. If an incorrect key is detected then nil is returned. 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 prefixCopy[blockSize-2] != prefixCopy[blockSize] || | ||||
| 		prefixCopy[blockSize-1] != prefixCopy[blockSize+1] { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	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++ | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										74
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/one_pass_signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/one_pass_signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| // 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" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/s2k" | ||||
| ) | ||||
|  | ||||
| // 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/keybase/go-crypto/openpgp/packet/opaque.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								vendor/github.com/keybase/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/keybase/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 | ||||
| } | ||||
							
								
								
									
										563
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/packet.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										563
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/packet.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,563 @@ | ||||
| // 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/keybase/go-crypto/openpgp/packet" | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"crypto/aes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/des" | ||||
| 	"crypto/elliptic" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/cast5" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
| 	lengthByte [1]byte | ||||
| } | ||||
|  | ||||
| func (w *partialLengthWriter) Write(p []byte) (n int, err error) { | ||||
| 	for len(p) > 0 { | ||||
| 		for power := uint(14); power < 32; power-- { | ||||
| 			l := 1 << power | ||||
| 			if len(p) >= 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(p[:l]) | ||||
| 				n += m | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				p = p[l:] | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (w *partialLengthWriter) Close() error { | ||||
| 	w.lengthByte[0] = 0 | ||||
| 	_, err := w.w.Write(w.lengthByte[:]) | ||||
| 	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) { | ||||
| 	var buf [6]byte | ||||
| 	var n int | ||||
|  | ||||
| 	buf[0] = 0x80 | 0x40 | byte(ptype) | ||||
| 	if length < 192 { | ||||
| 		buf[1] = byte(length) | ||||
| 		n = 2 | ||||
| 	} else if length < 8384 { | ||||
| 		length -= 192 | ||||
| 		buf[1] = 192 + byte(length>>8) | ||||
| 		buf[2] = byte(length) | ||||
| 		n = 3 | ||||
| 	} else { | ||||
| 		buf[1] = 255 | ||||
| 		buf[2] = byte(length >> 24) | ||||
| 		buf[3] = byte(length >> 16) | ||||
| 		buf[4] = byte(length >> 8) | ||||
| 		buf[5] = byte(length) | ||||
| 		n = 6 | ||||
| 	} | ||||
|  | ||||
| 	_, 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) { | ||||
| 	var buf [1]byte | ||||
| 	buf[0] = 0x80 | 0x40 | byte(ptype) | ||||
| 	_, err = w.Write(buf[:]) | ||||
| 	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 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| ) | ||||
|  | ||||
| // peekVersion detects the version of a public key packet about to | ||||
| // be read. A bufio.Reader at the original position of the io.Reader | ||||
| // is returned. | ||||
| func peekVersion(r io.Reader) (bufr *bufio.Reader, ver byte, err error) { | ||||
| 	bufr = bufio.NewReader(r) | ||||
| 	var verBuf []byte | ||||
| 	if verBuf, err = bufr.Peek(1); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	ver = verBuf[0] | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // 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: | ||||
| 		var version byte | ||||
| 		// Detect signature version | ||||
| 		if contents, version, err = peekVersion(contents); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if version < 4 { | ||||
| 			p = new(SignatureV3) | ||||
| 		} else { | ||||
| 			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: | ||||
| 		var version byte | ||||
| 		if contents, version, err = peekVersion(contents); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		isSubkey := tag == packetTypePublicSubkey | ||||
| 		if version < 4 { | ||||
| 			p = &PublicKeyV3{IsSubkey: isSubkey} | ||||
| 		} else { | ||||
| 			p = &PublicKey{IsSubkey: isSubkey} | ||||
| 		} | ||||
| 	case packetTypeCompressed: | ||||
| 		p = new(Compressed) | ||||
| 	case packetTypeSymmetricallyEncrypted: | ||||
| 		p = new(SymmetricallyEncrypted) | ||||
| 	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 | ||||
| 	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 = 0 | ||||
| 	SigTypeText                             = 1 | ||||
| 	SigTypeGenericCert                      = 0x10 | ||||
| 	SigTypePersonaCert                      = 0x11 | ||||
| 	SigTypeCasualCert                       = 0x12 | ||||
| 	SigTypePositiveCert                     = 0x13 | ||||
| 	SigTypeSubkeyBinding                    = 0x18 | ||||
| 	SigTypePrimaryKeyBinding                = 0x19 | ||||
| 	SigTypeDirectSignature                  = 0x1F | ||||
| 	SigTypeKeyRevocation                    = 0x20 | ||||
| 	SigTypeSubkeyRevocation                 = 0x28 | ||||
| 	SigTypeIdentityRevocation               = 0x30 | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
| 	PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 | ||||
| 	PubKeyAlgoRSASignOnly    PublicKeyAlgorithm = 3 | ||||
| 	PubKeyAlgoElGamal        PublicKeyAlgorithm = 16 | ||||
| 	PubKeyAlgoDSA            PublicKeyAlgorithm = 17 | ||||
| 	// RFC 6637, Section 5. | ||||
| 	PubKeyAlgoECDH  PublicKeyAlgorithm = 18 | ||||
| 	PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | ||||
| 	// RFC -1 | ||||
| 	PubKeyAlgoEdDSA PublicKeyAlgorithm = 22 | ||||
| ) | ||||
|  | ||||
| // 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 uint8 | ||||
|  | ||||
| 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 { | ||||
| 	switch cipher { | ||||
| 	case Cipher3DES: | ||||
| 		return 24 | ||||
| 	case CipherCAST5: | ||||
| 		return cast5.KeySize | ||||
| 	case CipherAES128: | ||||
| 		return 16 | ||||
| 	case CipherAES192: | ||||
| 		return 24 | ||||
| 	case CipherAES256: | ||||
| 		return 32 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // blockSize returns the block size, in bytes, of cipher. | ||||
| func (cipher CipherFunction) blockSize() int { | ||||
| 	switch cipher { | ||||
| 	case Cipher3DES: | ||||
| 		return des.BlockSize | ||||
| 	case CipherCAST5: | ||||
| 		return 8 | ||||
| 	case CipherAES128, CipherAES192, CipherAES256: | ||||
| 		return 16 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // new returns a fresh instance of the given cipher. | ||||
| func (cipher CipherFunction) new(key []byte) (block cipher.Block) { | ||||
| 	switch cipher { | ||||
| 	case Cipher3DES: | ||||
| 		block, _ = des.NewTripleDESCipher(key) | ||||
| 	case CipherCAST5: | ||||
| 		block, _ = cast5.NewCipher(key) | ||||
| 	case CipherAES128, CipherAES192, CipherAES256: | ||||
| 		block, _ = aes.NewCipher(key) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // readMPI reads a big integer from r. The bit length returned is the bit | ||||
| // length that was specified in r. This is preserved so that the integer can be | ||||
| // reserialized exactly. | ||||
| func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) { | ||||
| 	var buf [2]byte | ||||
| 	_, err = readFull(r, buf[0:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	bitLength = uint16(buf[0])<<8 | uint16(buf[1]) | ||||
| 	numBytes := (int(bitLength) + 7) / 8 | ||||
| 	mpi = make([]byte, numBytes) | ||||
| 	_, err = readFull(r, mpi) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // mpiLength returns the length of the given *big.Int when serialized as an | ||||
| // MPI. | ||||
| func mpiLength(n *big.Int) (mpiLengthInBytes int) { | ||||
| 	mpiLengthInBytes = 2 /* MPI length */ | ||||
| 	mpiLengthInBytes += (n.BitLen() + 7) / 8 | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // writeMPI serializes a big integer to w. | ||||
| func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { | ||||
| 	_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) | ||||
| 	if err == nil { | ||||
| 		_, err = w.Write(mpiBytes) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func WritePaddedBigInt(w io.Writer, length int, X *big.Int) (n int, err error) { | ||||
| 	bytes := X.Bytes() | ||||
| 	n1, err := w.Write(make([]byte, length-len(bytes))) | ||||
| 	if err != nil { | ||||
| 		return n1, err | ||||
| 	} | ||||
| 	n2, err := w.Write(bytes) | ||||
| 	if err != nil { | ||||
| 		return n2, err | ||||
| 	} | ||||
| 	return (n1 + n2), err | ||||
| } | ||||
|  | ||||
| // Minimum number of bytes to fit the curve coordinates. All | ||||
| // coordinates have to be 0-padded to this length. | ||||
| func mpiPointByteLength(curve elliptic.Curve) int { | ||||
| 	return (curve.Params().P.BitLen() + 7) / 8 | ||||
| } | ||||
|  | ||||
| // writeBig serializes a *big.Int to w. | ||||
| func writeBig(w io.Writer, i *big.Int) error { | ||||
| 	return writeMPI(w, uint16(i.BitLen()), i.Bytes()) | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| ) | ||||
							
								
								
									
										550
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										550
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,550 @@ | ||||
| // 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" | ||||
| 	"crypto/dsa" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/sha1" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/ed25519" | ||||
| 	"github.com/keybase/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/keybase/go-crypto/openpgp/elgamal" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/s2k" | ||||
| 	"github.com/keybase/go-crypto/rsa" | ||||
| ) | ||||
|  | ||||
| // 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) | ||||
| 	PrivateKey    interface{} // An *rsa.PrivateKey or *dsa.PrivateKey. | ||||
| 	sha1Checksum  bool | ||||
| 	iv            []byte | ||||
| 	s2kHeader     []byte | ||||
| } | ||||
|  | ||||
| type EdDSAPrivateKey struct { | ||||
| 	PrivateKey | ||||
| 	seed parsedMPI | ||||
| } | ||||
|  | ||||
| func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) { | ||||
| 	r := bytes.NewReader(e.seed.bytes) | ||||
| 	publicKey, privateKey, err := ed25519.GenerateKey(r) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if !bytes.Equal(publicKey, e.PublicKey.edk.p.bytes[1:]) { // [1:] because [0] is 0x40 mpi header | ||||
| 		return nil, nil, errors.UnsupportedError("EdDSA: Private key does not match public key.") | ||||
| 	} | ||||
|  | ||||
| 	sig := ed25519.Sign(privateKey, digest) | ||||
|  | ||||
| 	sigLen := ed25519.SignatureSize / 2 | ||||
| 	return sig[:sigLen], sig[sigLen:], nil | ||||
| } | ||||
|  | ||||
| func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewElGamalPrivateKey(currentTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewElGamalPublicKey(currentTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { | ||||
| 	pk := new(PrivateKey) | ||||
| 	pk.PublicKey = *NewECDSAPublicKey(currentTime, &priv.PublicKey) | ||||
| 	pk.PrivateKey = priv | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parse(r io.Reader) (err error) { | ||||
| 	err = (&pk.PublicKey).parse(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var buf [1]byte | ||||
| 	_, err = readFull(r, buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2kType := buf[0] | ||||
|  | ||||
| 	switch s2kType { | ||||
| 	case 0: | ||||
| 		pk.s2k = nil | ||||
| 		pk.Encrypted = false | ||||
| 	case 254, 255: | ||||
| 		_, err = readFull(r, buf[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.cipher = CipherFunction(buf[0]) | ||||
| 		pk.Encrypted = true | ||||
| 		pk.s2k, err = s2k.Parse(r) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if s2kType == 254 { | ||||
| 			pk.sha1Checksum = true | ||||
| 		} | ||||
| 		// S2K == nil implies that we got a "GNU Dummy" S2K. For instance, | ||||
| 		// because our master secret key is on a USB key in a vault somewhere. | ||||
| 		// In that case, there is no further data to consume here. | ||||
| 		if pk.s2k == nil { | ||||
| 			pk.Encrypted = false | ||||
| 			return | ||||
| 		} | ||||
| 	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 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	pk.encryptedData, err = ioutil.ReadAll(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if !pk.Encrypted { | ||||
| 		return pk.parsePrivateKey(pk.encryptedData) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func mod64kHash(d []byte) uint16 { | ||||
| 	var h uint16 | ||||
| 	for _, b := range d { | ||||
| 		h += uint16(b) | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| // Encrypt is the counterpart to the Decrypt() method below. It encrypts | ||||
| // the private key with the provided passphrase. If config is nil, then | ||||
| // the standard, and sensible, defaults apply. | ||||
| // | ||||
| // A key will be derived from the given passphrase using S2K Specifier | ||||
| // Type 3 (Iterated + Salted, see RFC-4880 Sec. 3.7.1.3). This choice | ||||
| // is hardcoded in s2k.Serialize(). S2KCount is hardcoded to 0, which is | ||||
| // equivalent to 65536. And the hash algorithm for key-derivation can be | ||||
| // set with config. The encrypted PrivateKey, using the algorithm specified | ||||
| // in config (if provided), is written out to the encryptedData member. | ||||
| // When Serialize() is called, this encryptedData member will be | ||||
| // serialized, using S2K Usage value of 254, and thus SHA1 checksum. | ||||
| func (pk *PrivateKey) Encrypt(passphrase []byte, config *Config) (err error) { | ||||
| 	if pk.PrivateKey == nil { | ||||
| 		return errors.InvalidArgumentError("there is no private key to encrypt") | ||||
| 	} | ||||
|  | ||||
| 	pk.sha1Checksum = true | ||||
| 	pk.cipher = config.Cipher() | ||||
| 	s2kConfig := s2k.Config{ | ||||
| 		Hash:     config.Hash(), | ||||
| 		S2KCount: 0, | ||||
| 	} | ||||
| 	s2kBuf := bytes.NewBuffer(nil) | ||||
| 	derivedKey := make([]byte, pk.cipher.KeySize()) | ||||
| 	err = s2k.Serialize(s2kBuf, derivedKey, config.Random(), passphrase, &s2kConfig) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	pk.s2kHeader = s2kBuf.Bytes() | ||||
| 	// No good way to set pk.s2k but to call s2k.Parse(), | ||||
| 	// even though we have all the information here, but | ||||
| 	// most of the functions needed are private to s2k. | ||||
| 	pk.s2k, err = s2k.Parse(s2kBuf) | ||||
| 	pk.iv = make([]byte, pk.cipher.blockSize()) | ||||
| 	if _, err = config.Random().Read(pk.iv); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	privateKeyBuf := bytes.NewBuffer(nil) | ||||
| 	if err = pk.serializePrivateKey(privateKeyBuf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	checksum := sha1.Sum(privateKeyBuf.Bytes()) | ||||
| 	if _, err = privateKeyBuf.Write(checksum[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	pkData := privateKeyBuf.Bytes() | ||||
| 	block := pk.cipher.new(derivedKey) | ||||
| 	pk.encryptedData = make([]byte, len(pkData)) | ||||
| 	cfb := cipher.NewCFBEncrypter(block, pk.iv) | ||||
| 	cfb.XORKeyStream(pk.encryptedData, pkData) | ||||
| 	pk.Encrypted = true | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) Serialize(w io.Writer) (err error) { | ||||
| 	buf := bytes.NewBuffer(nil) | ||||
| 	err = pk.PublicKey.serializeWithoutHeaders(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	privateKeyBuf := bytes.NewBuffer(nil) | ||||
|  | ||||
| 	if pk.PrivateKey == nil { | ||||
| 		_, err = buf.Write([]byte{ | ||||
| 			254,           // SHA-1 Convention | ||||
| 			9,             // Encryption scheme (AES256) | ||||
| 			101,           // GNU Extensions | ||||
| 			2,             // Hash value (SHA1) | ||||
| 			'G', 'N', 'U', // "GNU" as a string | ||||
| 			1, // Extension type 1001 (minus 1000) | ||||
| 		}) | ||||
| 	} else if pk.Encrypted { | ||||
| 		_, err = buf.Write([]byte{ | ||||
| 			254,             // SHA-1 Convention | ||||
| 			byte(pk.cipher), // Encryption scheme | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err = buf.Write(pk.s2kHeader); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err = buf.Write(pk.iv); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err = privateKeyBuf.Write(pk.encryptedData); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else { | ||||
| 		buf.WriteByte(0 /* no encryption */) | ||||
| 		if err = pk.serializePrivateKey(privateKeyBuf); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ptype := packetTypePrivateKey | ||||
| 	contents := buf.Bytes() | ||||
| 	privateKeyBytes := privateKeyBuf.Bytes() | ||||
| 	if pk.IsSubkey { | ||||
| 		ptype = packetTypePrivateSubkey | ||||
| 	} | ||||
| 	totalLen := len(contents) + len(privateKeyBytes) | ||||
| 	if !pk.Encrypted { | ||||
| 		totalLen += 2 | ||||
| 	} | ||||
| 	err = serializeHeader(w, ptype, totalLen) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(contents) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(privateKeyBytes) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if len(privateKeyBytes) > 0 && !pk.Encrypted { | ||||
| 		checksum := mod64kHash(privateKeyBytes) | ||||
| 		var checksumBytes [2]byte | ||||
| 		checksumBytes[0] = byte(checksum >> 8) | ||||
| 		checksumBytes[1] = byte(checksum) | ||||
| 		_, err = w.Write(checksumBytes[:]) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| 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 *ecdh.PrivateKey: | ||||
| 		err = serializeECDHPrivateKey(w, priv) | ||||
| 	case *EdDSAPrivateKey: | ||||
| 		err = serializeEdDSAPrivateKey(w, priv) | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("unknown private key type") | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error { | ||||
| 	err := writeBig(w, priv.D) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = writeBig(w, priv.Primes[1]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = writeBig(w, priv.Primes[0]) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return writeBig(w, priv.Precomputed.Qinv) | ||||
| } | ||||
|  | ||||
| func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error { | ||||
| 	return writeBig(w, priv.X) | ||||
| } | ||||
|  | ||||
| func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error { | ||||
| 	return writeBig(w, priv.X) | ||||
| } | ||||
|  | ||||
| func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error { | ||||
| 	return writeBig(w, priv.D) | ||||
| } | ||||
|  | ||||
| func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error { | ||||
| 	return writeBig(w, priv.X) | ||||
| } | ||||
|  | ||||
| func serializeEdDSAPrivateKey(w io.Writer, priv *EdDSAPrivateKey) error { | ||||
| 	return writeMPI(w, priv.seed.bitLength, priv.seed.bytes) | ||||
| } | ||||
|  | ||||
| // Decrypt decrypts an encrypted private key using a passphrase. | ||||
| func (pk *PrivateKey) Decrypt(passphrase []byte) error { | ||||
| 	if !pk.Encrypted { | ||||
| 		return nil | ||||
| 	} | ||||
| 	// For GNU Dummy S2K, there's no key here, so don't do anything. | ||||
| 	if pk.s2k == nil { | ||||
| 		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] | ||||
| 	} | ||||
|  | ||||
| 	return pk.parsePrivateKey(data) | ||||
| } | ||||
|  | ||||
| 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, _, err := readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	p, _, err := readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	q, _, err := readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	rsaPriv.D = new(big.Int).SetBytes(d) | ||||
| 	rsaPriv.Primes = make([]*big.Int, 2) | ||||
| 	rsaPriv.Primes[0] = new(big.Int).SetBytes(p) | ||||
| 	rsaPriv.Primes[1] = new(big.Int).SetBytes(q) | ||||
| 	if err := rsaPriv.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	rsaPriv.Precompute() | ||||
| 	pk.PrivateKey = rsaPriv | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
|  | ||||
| 	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, _, err := readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	dsaPriv.X = new(big.Int).SetBytes(x) | ||||
| 	pk.PrivateKey = dsaPriv | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
|  | ||||
| 	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, _, err := readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	priv.X = new(big.Int).SetBytes(x) | ||||
| 	pk.PrivateKey = priv | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) { | ||||
| 	pub := pk.PublicKey.PublicKey.(*ecdh.PublicKey) | ||||
| 	priv := new(ecdh.PrivateKey) | ||||
| 	priv.PublicKey = *pub | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	d, _, err := readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	priv.X = new(big.Int).SetBytes(d) | ||||
| 	pk.PrivateKey = priv | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
| 	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, _, err := readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ecdsaPriv.D = new(big.Int).SetBytes(d) | ||||
| 	pk.PrivateKey = ecdsaPriv | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) { | ||||
| 	eddsaPriv := new(EdDSAPrivateKey) | ||||
| 	eddsaPriv.PublicKey = pk.PublicKey | ||||
|  | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	eddsaPriv.seed.bytes, eddsaPriv.seed.bitLength, err = readMPI(buf) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if bLen := len(eddsaPriv.seed.bytes); bLen != 32 { // 32 bytes private part of ed25519 key. | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA private key length: %d", bLen)) | ||||
| 	} | ||||
|  | ||||
| 	pk.PrivateKey = eddsaPriv | ||||
| 	pk.Encrypted = false | ||||
| 	pk.encryptedData = nil | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										930
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/public_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										930
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/public_key.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,930 @@ | ||||
| // 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" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/sha1" | ||||
| 	_ "crypto/sha256" | ||||
| 	_ "crypto/sha512" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/brainpool" | ||||
| 	"github.com/keybase/go-crypto/curve25519" | ||||
| 	"github.com/keybase/go-crypto/ed25519" | ||||
| 	"github.com/keybase/go-crypto/openpgp/ecdh" | ||||
| 	"github.com/keybase/go-crypto/openpgp/elgamal" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/rsa" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// NIST curve P-256 | ||||
| 	oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07} | ||||
| 	// NIST curve P-384 | ||||
| 	oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22} | ||||
| 	// NIST curve P-521 | ||||
| 	oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23} | ||||
| 	// Brainpool curve P-256r1 | ||||
| 	oidCurveP256r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07} | ||||
| 	// Brainpool curve P-384r1 | ||||
| 	oidCurveP384r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B} | ||||
| 	// Brainpool curve P-512r1 | ||||
| 	oidCurveP512r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D} | ||||
| 	// EdDSA | ||||
| 	oidEdDSA []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01} | ||||
| 	// cv25519 | ||||
| 	oidCurve25519 []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01} | ||||
| ) | ||||
|  | ||||
| const maxOIDLength = 10 | ||||
|  | ||||
| // ecdsaKey stores the algorithm-specific fields for ECDSA keys. | ||||
| // as defined in RFC 6637, Section 9. | ||||
| type ecdsaKey struct { | ||||
| 	// oid contains the OID byte sequence identifying the elliptic curve used | ||||
| 	oid []byte | ||||
| 	// p contains the elliptic curve point that represents the public key | ||||
| 	p parsedMPI | ||||
| } | ||||
|  | ||||
| type edDSAkey struct { | ||||
| 	ecdsaKey | ||||
| } | ||||
|  | ||||
| func copyFrontFill(dst, src []byte, length int) int { | ||||
| 	if srcLen := len(src); srcLen < length { | ||||
| 		return copy(dst[length-srcLen:], src[:]) | ||||
| 	} else { | ||||
| 		return copy(dst[:], src[:]) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (e *edDSAkey) Verify(payload []byte, r parsedMPI, s parsedMPI) bool { | ||||
| 	const halfSigSize = ed25519.SignatureSize / 2 | ||||
| 	var sig [ed25519.SignatureSize]byte | ||||
|  | ||||
| 	// NOTE: The first byte is 0x40 - MPI header | ||||
| 	// TODO: Maybe clean the code up and use 0x40 as a header when | ||||
| 	// reading and keep only actual number in p field. Find out how | ||||
| 	// other MPIs are stored. | ||||
| 	key := e.p.bytes[1:] | ||||
|  | ||||
| 	// Note: it may happen that R + S do not form 64-byte signature buffer that | ||||
| 	// ed25519 expects, but because we copy it over to an array of exact size, | ||||
| 	// we will always pass correctly sized slice to Verify. Slice too short | ||||
| 	// would make ed25519 panic(). | ||||
| 	copyFrontFill(sig[:halfSigSize], r.bytes, halfSigSize) | ||||
| 	copyFrontFill(sig[halfSigSize:], s.bytes, halfSigSize) | ||||
|  | ||||
| 	return ed25519.Verify(key, payload, sig[:]) | ||||
| } | ||||
|  | ||||
| // parseOID reads the OID for the curve as defined in RFC 6637, Section 9. | ||||
| func parseOID(r io.Reader) (oid []byte, err error) { | ||||
| 	buf := make([]byte, maxOIDLength) | ||||
| 	if _, err = readFull(r, buf[:1]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	oidLen := buf[0] | ||||
| 	if int(oidLen) > len(buf) { | ||||
| 		err = errors.UnsupportedError("invalid oid length: " + strconv.Itoa(int(oidLen))) | ||||
| 		return | ||||
| 	} | ||||
| 	oid = buf[:oidLen] | ||||
| 	_, err = readFull(r, oid) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (f *ecdsaKey) parse(r io.Reader) (err error) { | ||||
| 	if f.oid, err = parseOID(r); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	f.p.bytes, f.p.bitLength, err = readMPI(r) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (f *ecdsaKey) serialize(w io.Writer) (err error) { | ||||
| 	buf := make([]byte, maxOIDLength+1) | ||||
| 	buf[0] = byte(len(f.oid)) | ||||
| 	copy(buf[1:], f.oid) | ||||
| 	if _, err = w.Write(buf[:len(f.oid)+1]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return writeMPIs(w, f.p) | ||||
| } | ||||
|  | ||||
| func getCurveByOid(oid []byte) elliptic.Curve { | ||||
| 	switch { | ||||
| 	case bytes.Equal(oid, oidCurveP256): | ||||
| 		return elliptic.P256() | ||||
| 	case bytes.Equal(oid, oidCurveP384): | ||||
| 		return elliptic.P384() | ||||
| 	case bytes.Equal(oid, oidCurveP521): | ||||
| 		return elliptic.P521() | ||||
| 	case bytes.Equal(oid, oidCurveP256r1): | ||||
| 		return brainpool.P256r1() | ||||
| 	case bytes.Equal(oid, oidCurveP384r1): | ||||
| 		return brainpool.P384r1() | ||||
| 	case bytes.Equal(oid, oidCurveP512r1): | ||||
| 		return brainpool.P512r1() | ||||
| 	case bytes.Equal(oid, oidCurve25519): | ||||
| 		return curve25519.Cv25519() | ||||
| 	default: | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) { | ||||
| 	var c = getCurveByOid(f.oid) | ||||
| 	// Curve25519 should not be used in ECDSA. | ||||
| 	if c == nil || bytes.Equal(f.oid, oidCurve25519) { | ||||
| 		return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) | ||||
| 	} | ||||
| 	// Note: Unmarshal already checks if point is on curve. | ||||
| 	x, y := elliptic.Unmarshal(c, f.p.bytes) | ||||
| 	if x == nil { | ||||
| 		return nil, errors.UnsupportedError("failed to parse EC point") | ||||
| 	} | ||||
| 	return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil | ||||
| } | ||||
|  | ||||
| func (f *ecdsaKey) newECDH() (*ecdh.PublicKey, error) { | ||||
| 	var c = getCurveByOid(f.oid) | ||||
| 	if c == nil { | ||||
| 		return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) | ||||
| 	} | ||||
| 	// ecdh.Unmarshal handles unmarshaling for all curve types. It | ||||
| 	// also checks if point is on curve. | ||||
| 	x, y := ecdh.Unmarshal(c, f.p.bytes) | ||||
| 	if x == nil { | ||||
| 		return nil, errors.UnsupportedError("failed to parse EC point") | ||||
| 	} | ||||
| 	return &ecdh.PublicKey{Curve: c, X: x, Y: y}, nil | ||||
| } | ||||
|  | ||||
| func (f *ecdsaKey) byteLen() int { | ||||
| 	return 1 + len(f.oid) + 2 + len(f.p.bytes) | ||||
| } | ||||
|  | ||||
| type kdfHashFunction byte | ||||
| type kdfAlgorithm byte | ||||
|  | ||||
| // ecdhKdf stores key derivation function parameters | ||||
| // used for ECDH encryption. See RFC 6637, Section 9. | ||||
| type ecdhKdf struct { | ||||
| 	KdfHash kdfHashFunction | ||||
| 	KdfAlgo kdfAlgorithm | ||||
| } | ||||
|  | ||||
| func (f *ecdhKdf) parse(r io.Reader) (err error) { | ||||
| 	buf := make([]byte, 1) | ||||
| 	if _, err = readFull(r, buf); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	kdfLen := int(buf[0]) | ||||
| 	if kdfLen < 3 { | ||||
| 		return errors.UnsupportedError("Unsupported ECDH KDF length: " + strconv.Itoa(kdfLen)) | ||||
| 	} | ||||
| 	buf = make([]byte, kdfLen) | ||||
| 	if _, err = readFull(r, buf); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	reserved := int(buf[0]) | ||||
| 	f.KdfHash = kdfHashFunction(buf[1]) | ||||
| 	f.KdfAlgo = kdfAlgorithm(buf[2]) | ||||
| 	if reserved != 0x01 { | ||||
| 		return errors.UnsupportedError("Unsupported KDF reserved field: " + strconv.Itoa(reserved)) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (f *ecdhKdf) serialize(w io.Writer) (err error) { | ||||
| 	buf := make([]byte, 4) | ||||
| 	// See RFC 6637, Section 9, Algorithm-Specific Fields for ECDH keys. | ||||
| 	buf[0] = byte(0x03) // Length of the following fields | ||||
| 	buf[1] = byte(0x01) // Reserved for future extensions, must be 1 for now | ||||
| 	buf[2] = byte(f.KdfHash) | ||||
| 	buf[3] = byte(f.KdfAlgo) | ||||
| 	_, err = w.Write(buf[:]) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (f *ecdhKdf) byteLen() int { | ||||
| 	return 4 | ||||
| } | ||||
|  | ||||
| // PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2. | ||||
| type PublicKey struct { | ||||
| 	CreationTime time.Time | ||||
| 	PubKeyAlgo   PublicKeyAlgorithm | ||||
| 	PublicKey    interface{} // *rsa.PublicKey, *dsa.PublicKey or *ecdsa.PublicKey | ||||
| 	Fingerprint  [20]byte | ||||
| 	KeyId        uint64 | ||||
| 	IsSubkey     bool | ||||
|  | ||||
| 	n, e, p, q, g, y parsedMPI | ||||
|  | ||||
| 	// RFC 6637 fields | ||||
| 	ec   *ecdsaKey | ||||
| 	ecdh *ecdhKdf | ||||
|  | ||||
| 	// EdDSA fields (no RFC available), uses ecdsa scaffolding | ||||
| 	edk *edDSAkey | ||||
| } | ||||
|  | ||||
| // signingKey provides a convenient abstraction over signature verification | ||||
| // for v3 and v4 public keys. | ||||
| type signingKey interface { | ||||
| 	SerializeSignaturePrefix(io.Writer) | ||||
| 	serializeWithoutHeaders(io.Writer) error | ||||
| } | ||||
|  | ||||
| func FromBig(n *big.Int) parsedMPI { | ||||
| 	return parsedMPI{ | ||||
| 		bytes:     n.Bytes(), | ||||
| 		bitLength: uint16(n.BitLen()), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func FromBytes(bytes []byte) parsedMPI { | ||||
| 	return parsedMPI{ | ||||
| 		bytes:     bytes, | ||||
| 		bitLength: uint16(8 * len(bytes)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. | ||||
| func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoRSA, | ||||
| 		PublicKey:    pub, | ||||
| 		n:            FromBig(pub.N), | ||||
| 		e:            FromBig(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{ | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            FromBig(pub.P), | ||||
| 		q:            FromBig(pub.Q), | ||||
| 		g:            FromBig(pub.G), | ||||
| 		y:            FromBig(pub.Y), | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerPrintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| // check EdDSA public key material. | ||||
| // There is currently no RFC for it, but it doesn't mean it's not | ||||
| // implemented or in use. | ||||
| func (e *edDSAkey) check() error { | ||||
| 	if !bytes.Equal(e.oid, oidEdDSA) { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("Bad OID for EdDSA key: %v", e.oid)) | ||||
| 	} | ||||
| 	if bLen := len(e.p.bytes); bLen != 33 { // 32 bytes for ed25519 key and 1 byte for 0x40 header | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA public key length: %d", bLen)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey. | ||||
| func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoElGamal, | ||||
| 		PublicKey:    pub, | ||||
| 		p:            FromBig(pub.P), | ||||
| 		g:            FromBig(pub.G), | ||||
| 		y:            FromBig(pub.Y), | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerPrintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { | ||||
| 	pk := &PublicKey{ | ||||
| 		CreationTime: creationTime, | ||||
| 		PubKeyAlgo:   PubKeyAlgoECDSA, | ||||
| 		PublicKey:    pub, | ||||
| 		ec:           new(ecdsaKey), | ||||
| 	} | ||||
| 	switch pub.Curve { | ||||
| 	case elliptic.P256(): | ||||
| 		pk.ec.oid = oidCurveP256 | ||||
| 	case elliptic.P384(): | ||||
| 		pk.ec.oid = oidCurveP384 | ||||
| 	case elliptic.P521(): | ||||
| 		pk.ec.oid = oidCurveP521 | ||||
| 	case brainpool.P256r1(): | ||||
| 		pk.ec.oid = oidCurveP256r1 | ||||
| 	case brainpool.P384r1(): | ||||
| 		pk.ec.oid = oidCurveP384r1 | ||||
| 	case brainpool.P512r1(): | ||||
| 		pk.ec.oid = oidCurveP512r1 | ||||
| 	} | ||||
| 	pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) | ||||
| 	pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes)) | ||||
|  | ||||
| 	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 { | ||||
| 		return errors.UnsupportedError("public key version") | ||||
| 	} | ||||
| 	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 PubKeyAlgoEdDSA: | ||||
| 		pk.edk = new(edDSAkey) | ||||
| 		if err = pk.edk.parse(r); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		err = pk.edk.check() | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		pk.ec = new(ecdsaKey) | ||||
| 		if err = pk.ec.parse(r); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		pk.PublicKey, err = pk.ec.newECDSA() | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		pk.ec = new(ecdsaKey) | ||||
| 		if err = pk.ec.parse(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.ecdh = new(ecdhKdf) | ||||
| 		if err = pk.ecdh.parse(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		pk.PublicKey, err = pk.ec.newECDH() | ||||
| 	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 | ||||
| 	fingerPrint := sha1.New() | ||||
| 	pk.SerializeSignaturePrefix(fingerPrint) | ||||
| 	pk.serializeWithoutHeaders(fingerPrint) | ||||
| 	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.bytes, pk.n.bitLength, err = readMPI(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.e.bytes, pk.e.bitLength, err = readMPI(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if len(pk.e.bytes) > 7 { | ||||
| 		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 |= int64(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.bytes, pk.p.bitLength, err = readMPI(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.q.bytes, pk.q.bitLength, err = readMPI(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.g.bytes, pk.g.bitLength, err = readMPI(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.y.bytes, pk.y.bitLength, err = readMPI(r) | ||||
| 	if 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.bytes, pk.p.bitLength, err = readMPI(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.g.bytes, pk.g.bitLength, err = readMPI(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pk.y.bytes, pk.y.bitLength, err = readMPI(r) | ||||
| 	if 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 | ||||
| } | ||||
|  | ||||
| // 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(h io.Writer) { | ||||
| 	var pLength uint16 | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		pLength += 2 + uint16(len(pk.n.bytes)) | ||||
| 		pLength += 2 + uint16(len(pk.e.bytes)) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		pLength += 2 + uint16(len(pk.p.bytes)) | ||||
| 		pLength += 2 + uint16(len(pk.q.bytes)) | ||||
| 		pLength += 2 + uint16(len(pk.g.bytes)) | ||||
| 		pLength += 2 + uint16(len(pk.y.bytes)) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		pLength += 2 + uint16(len(pk.p.bytes)) | ||||
| 		pLength += 2 + uint16(len(pk.g.bytes)) | ||||
| 		pLength += 2 + uint16(len(pk.y.bytes)) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		pLength += uint16(pk.ec.byteLen()) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		pLength += uint16(pk.ec.byteLen()) | ||||
| 		pLength += uint16(pk.ecdh.byteLen()) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		pLength += uint16(pk.edk.byteLen()) | ||||
| 	default: | ||||
| 		panic("unknown public key algorithm") | ||||
| 	} | ||||
| 	pLength += 6 | ||||
| 	h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (pk *PublicKey) Serialize(w io.Writer) (err error) { | ||||
| 	length := 6 // 6 byte header | ||||
|  | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		length += 2 + len(pk.n.bytes) | ||||
| 		length += 2 + len(pk.e.bytes) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		length += 2 + len(pk.p.bytes) | ||||
| 		length += 2 + len(pk.q.bytes) | ||||
| 		length += 2 + len(pk.g.bytes) | ||||
| 		length += 2 + len(pk.y.bytes) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		length += 2 + len(pk.p.bytes) | ||||
| 		length += 2 + len(pk.g.bytes) | ||||
| 		length += 2 + len(pk.y.bytes) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		length += pk.ec.byteLen() | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		length += pk.ec.byteLen() | ||||
| 		length += pk.ecdh.byteLen() | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		length += pk.edk.byteLen() | ||||
| 	default: | ||||
| 		panic("unknown public key algorithm") | ||||
| 	} | ||||
|  | ||||
| 	packetType := packetTypePublicKey | ||||
| 	if pk.IsSubkey { | ||||
| 		packetType = packetTypePublicSubkey | ||||
| 	} | ||||
| 	err = serializeHeader(w, packetType, length) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return pk.serializeWithoutHeaders(w) | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	var buf [6]byte | ||||
| 	buf[0] = 4 | ||||
| 	t := uint32(pk.CreationTime.Unix()) | ||||
| 	buf[1] = byte(t >> 24) | ||||
| 	buf[2] = byte(t >> 16) | ||||
| 	buf[3] = byte(t >> 8) | ||||
| 	buf[4] = byte(t) | ||||
| 	buf[5] = byte(pk.PubKeyAlgo) | ||||
|  | ||||
| 	_, err = w.Write(buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		return writeMPIs(w, pk.n, pk.e) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		return writeMPIs(w, pk.p, pk.q, pk.g, pk.y) | ||||
| 	case PubKeyAlgoElGamal: | ||||
| 		return writeMPIs(w, pk.p, pk.g, pk.y) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		return pk.ec.serialize(w) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		return pk.edk.serialize(w) | ||||
| 	case PubKeyAlgoECDH: | ||||
| 		if err = pk.ec.serialize(w); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		return pk.ecdh.serialize(w) | ||||
| 	} | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| // 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") | ||||
| 	} | ||||
|  | ||||
| 	signed.Write(sig.HashSuffix) | ||||
| 	hashBytes := signed.Sum(nil) | ||||
|  | ||||
| 	// NOTE(maxtaco) 2016-08-22 | ||||
| 	// | ||||
| 	// We used to do this: | ||||
| 	// | ||||
| 	// if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { | ||||
| 	//	  return errors.SignatureError("hash tag doesn't match") | ||||
| 	// } | ||||
| 	// | ||||
| 	// But don't do anything in this case. Some GPGs generate bad | ||||
| 	// 2-byte hash prefixes, but GPG also doesn't seem to care on | ||||
| 	// import. See BrentMaxwell's key. I think it's safe to disable | ||||
| 	// this check! | ||||
|  | ||||
| 	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, 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: | ||||
| 		if !pk.edk.Verify(hashBytes, sig.EdDSASigR, sig.EdDSASigS) { | ||||
| 			return errors.SignatureError("EdDSA verification failure") | ||||
| 		} | ||||
| 		return nil | ||||
| 	default: | ||||
| 		return errors.SignatureError("Unsupported public key algorithm used in signature") | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // VerifySignatureV3 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) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { | ||||
| 	if !pk.CanSign() { | ||||
| 		return errors.InvalidArgumentError("public key cannot generate signatures") | ||||
| 	} | ||||
|  | ||||
| 	suffix := make([]byte, 5) | ||||
| 	suffix[0] = byte(sig.SigType) | ||||
| 	binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) | ||||
| 	signed.Write(suffix) | ||||
| 	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) | ||||
| 		if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { | ||||
| 			return errors.SignatureError("RSA verification failure") | ||||
| 		} | ||||
| 		return | ||||
| 	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 | ||||
| 	default: | ||||
| 		panic("shouldn't happen") | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // 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() | ||||
|  | ||||
| 	updateKeySignatureHash(pk, signed, h) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // updateKeySignatureHash does the actual hash updates for keySignatureHash. | ||||
| func updateKeySignatureHash(pk, signed signingKey, h hash.Hash) { | ||||
| 	// RFC 4880, section 5.2.4 | ||||
| 	pk.SerializeSignaturePrefix(h) | ||||
| 	pk.serializeWithoutHeaders(h) | ||||
| 	signed.SerializeSignaturePrefix(h) | ||||
| 	signed.serializeWithoutHeaders(h) | ||||
| } | ||||
|  | ||||
| // 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 { | ||||
|  | ||||
| 		// BUG(maxtaco) | ||||
| 		// | ||||
| 		// We should check for more than FlagsSign here, because if | ||||
| 		// you read keys.go, we can sometimes use signing subkeys even if they're | ||||
| 		// not explicitly flagged as such. However, so doing fails lots of currently | ||||
| 		// working tests, so I'm not going to do much here. | ||||
| 		// | ||||
| 		// In other words, we should have this disjunction in the condition above: | ||||
| 		// | ||||
| 		//    || (!sig.FlagsValid && pk.PubKeyAlgo.CanSign()) { | ||||
| 		// | ||||
|  | ||||
| 		// 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 | ||||
| 	pk.SerializeSignaturePrefix(h) | ||||
| 	pk.serializeWithoutHeaders(h) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // VerifyRevocationSignature returns nil iff sig is a valid signature, made by this | ||||
| // public key. | ||||
| func (pk *PublicKey) VerifyRevocationSignature(revokedKey *PublicKey, sig *Signature) (err error) { | ||||
| 	h, err := keyRevocationHash(revokedKey, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignature(h, sig) | ||||
| } | ||||
|  | ||||
| type teeHash struct { | ||||
| 	h hash.Hash | ||||
| } | ||||
|  | ||||
| func (t teeHash) Write(b []byte) (n int, err error) { | ||||
| 	fmt.Printf("hash -> %s %+v\n", string(b), b) | ||||
| 	return t.h.Write(b) | ||||
| } | ||||
| func (t teeHash) Sum(b []byte) []byte { return t.h.Sum(b) } | ||||
| func (t teeHash) Reset()              { t.h.Reset() } | ||||
| func (t teeHash) Size() int           { return t.h.Size() } | ||||
| func (t teeHash) BlockSize() int      { return t.h.BlockSize() } | ||||
|  | ||||
| // 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() | ||||
|  | ||||
| 	updateUserIdSignatureHash(id, pk, h) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // updateUserIdSignatureHash does the actual hash updates for | ||||
| // userIdSignatureHash. | ||||
| func updateUserIdSignatureHash(id string, pk *PublicKey, h hash.Hash) { | ||||
| 	// 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) | ||||
| } | ||||
|  | ||||
| // VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this | ||||
| // public key, that id is the identity of pub. | ||||
| func (pk *PublicKey) VerifyUserIdSignatureV3(id string, pub *PublicKey, sig *SignatureV3) (err error) { | ||||
| 	h, err := userIdSignatureV3Hash(id, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignatureV3(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]) | ||||
| } | ||||
|  | ||||
| // A parsedMPI is used to store the contents of a big integer, along with the | ||||
| // bit length that was specified in the original input. This allows the MPI to | ||||
| // be reserialized exactly. | ||||
| type parsedMPI struct { | ||||
| 	bytes     []byte | ||||
| 	bitLength uint16 | ||||
| } | ||||
|  | ||||
| // writeMPIs is a utility function for serializing several big integers to the | ||||
| // given Writer. | ||||
| func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) { | ||||
| 	for _, mpi := range mpis { | ||||
| 		err = writeMPI(w, mpi.bitLength, mpi.bytes) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // BitLength returns the bit length for the given public key. Used for | ||||
| // displaying key information, actual buffers and BigInts inside may | ||||
| // have non-matching different size if the key is invalid. | ||||
| 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 PubKeyAlgoECDH: | ||||
| 		ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey) | ||||
| 		bitLength = uint16(ecdhPublicKey.Curve.Params().BitSize) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) | ||||
| 		bitLength = uint16(ecdsaPublicKey.Curve.Params().BitSize) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		// EdDSA only support ed25519 curves right now, just return | ||||
| 		// the length. Also, we don't have any PublicKey.Curve object | ||||
| 		// to look the size up from. | ||||
| 		bitLength = 256 | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("bad public-key algorithm") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										280
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/public_key_v3.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/public_key_v3.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,280 @@ | ||||
| // 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 ( | ||||
| 	"crypto" | ||||
| 	"crypto/md5" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/rsa" | ||||
| ) | ||||
|  | ||||
| // PublicKeyV3 represents older, version 3 public keys. These keys are less secure and | ||||
| // should not be used for signing or encrypting. They are supported here only for | ||||
| // parsing version 3 key material and validating signatures. | ||||
| // See RFC 4880, section 5.5.2. | ||||
| type PublicKeyV3 struct { | ||||
| 	CreationTime time.Time | ||||
| 	DaysToExpire uint16 | ||||
| 	PubKeyAlgo   PublicKeyAlgorithm | ||||
| 	PublicKey    *rsa.PublicKey | ||||
| 	Fingerprint  [16]byte | ||||
| 	KeyId        uint64 | ||||
| 	IsSubkey     bool | ||||
|  | ||||
| 	n, e parsedMPI | ||||
| } | ||||
|  | ||||
| // newRSAPublicKeyV3 returns a PublicKey that wraps the given rsa.PublicKey. | ||||
| // Included here for testing purposes only. RFC 4880, section 5.5.2: | ||||
| // "an implementation MUST NOT generate a V3 key, but MAY accept it." | ||||
| func newRSAPublicKeyV3(creationTime time.Time, pub *rsa.PublicKey) *PublicKeyV3 { | ||||
| 	pk := &PublicKeyV3{ | ||||
| 		CreationTime: creationTime, | ||||
| 		PublicKey:    pub, | ||||
| 		n:            FromBig(pub.N), | ||||
| 		e:            FromBig(big.NewInt(int64(pub.E))), | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerPrintAndKeyId() | ||||
| 	return pk | ||||
| } | ||||
|  | ||||
| func (pk *PublicKeyV3) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.5.2 | ||||
| 	var buf [8]byte | ||||
| 	if _, err = readFull(r, buf[:]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] < 2 || buf[0] > 3 { | ||||
| 		return errors.UnsupportedError("public key version") | ||||
| 	} | ||||
| 	pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) | ||||
| 	pk.DaysToExpire = binary.BigEndian.Uint16(buf[5:7]) | ||||
| 	pk.PubKeyAlgo = PublicKeyAlgorithm(buf[7]) | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		err = pk.parseRSA(r) | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	pk.setFingerPrintAndKeyId() | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (pk *PublicKeyV3) setFingerPrintAndKeyId() { | ||||
| 	// RFC 4880, section 12.2 | ||||
| 	fingerPrint := md5.New() | ||||
| 	fingerPrint.Write(pk.n.bytes) | ||||
| 	fingerPrint.Write(pk.e.bytes) | ||||
| 	fingerPrint.Sum(pk.Fingerprint[:0]) | ||||
| 	pk.KeyId = binary.BigEndian.Uint64(pk.n.bytes[len(pk.n.bytes)-8:]) | ||||
| } | ||||
|  | ||||
| // parseRSA parses RSA public key material from the given Reader. See RFC 4880, | ||||
| // section 5.5.2. | ||||
| func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) { | ||||
| 	if pk.n.bytes, pk.n.bitLength, err = readMPI(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if pk.e.bytes, pk.e.bitLength, err = readMPI(r); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// RFC 4880 Section 12.2 requires the low 8 bytes of the | ||||
| 	// modulus to form the key id. | ||||
| 	if len(pk.n.bytes) < 8 { | ||||
| 		return errors.StructuralError("v3 public key modulus is too short") | ||||
| 	} | ||||
| 	if len(pk.e.bytes) > 7 { | ||||
| 		err = errors.UnsupportedError("large public exponent") | ||||
| 		return | ||||
| 	} | ||||
| 	rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} | ||||
| 	for i := 0; i < len(pk.e.bytes); i++ { | ||||
| 		rsa.E <<= 8 | ||||
| 		rsa.E |= int64(pk.e.bytes[i]) | ||||
| 	} | ||||
| 	pk.PublicKey = rsa | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // 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 *PublicKeyV3) SerializeSignaturePrefix(w io.Writer) { | ||||
| 	var pLength uint16 | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		pLength += 2 + uint16(len(pk.n.bytes)) | ||||
| 		pLength += 2 + uint16(len(pk.e.bytes)) | ||||
| 	default: | ||||
| 		panic("unknown public key algorithm") | ||||
| 	} | ||||
| 	pLength += 6 | ||||
| 	w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (pk *PublicKeyV3) Serialize(w io.Writer) (err error) { | ||||
| 	length := 8 // 8 byte header | ||||
|  | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		length += 2 + len(pk.n.bytes) | ||||
| 		length += 2 + len(pk.e.bytes) | ||||
| 	default: | ||||
| 		panic("unknown public key algorithm") | ||||
| 	} | ||||
|  | ||||
| 	packetType := packetTypePublicKey | ||||
| 	if pk.IsSubkey { | ||||
| 		packetType = packetTypePublicSubkey | ||||
| 	} | ||||
| 	if err = serializeHeader(w, packetType, length); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return pk.serializeWithoutHeaders(w) | ||||
| } | ||||
|  | ||||
| // serializeWithoutHeaders marshals the PublicKey to w in the form of an | ||||
| // OpenPGP public key packet, not including the packet header. | ||||
| func (pk *PublicKeyV3) serializeWithoutHeaders(w io.Writer) (err error) { | ||||
| 	var buf [8]byte | ||||
| 	// Version 3 | ||||
| 	buf[0] = 3 | ||||
| 	// Creation time | ||||
| 	t := uint32(pk.CreationTime.Unix()) | ||||
| 	buf[1] = byte(t >> 24) | ||||
| 	buf[2] = byte(t >> 16) | ||||
| 	buf[3] = byte(t >> 8) | ||||
| 	buf[4] = byte(t) | ||||
| 	// Days to expire | ||||
| 	buf[5] = byte(pk.DaysToExpire >> 8) | ||||
| 	buf[6] = byte(pk.DaysToExpire) | ||||
| 	// Public key algorithm | ||||
| 	buf[7] = byte(pk.PubKeyAlgo) | ||||
|  | ||||
| 	if _, err = w.Write(buf[:]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		return writeMPIs(w, pk.n, pk.e) | ||||
| 	} | ||||
| 	return errors.InvalidArgumentError("bad public-key algorithm") | ||||
| } | ||||
|  | ||||
| // CanSign returns true iff this public key can generate signatures | ||||
| func (pk *PublicKeyV3) CanSign() bool { | ||||
| 	return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly | ||||
| } | ||||
|  | ||||
| // VerifySignatureV3 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 *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { | ||||
| 	if !pk.CanSign() { | ||||
| 		return errors.InvalidArgumentError("public key cannot generate signatures") | ||||
| 	} | ||||
|  | ||||
| 	suffix := make([]byte, 5) | ||||
| 	suffix[0] = byte(sig.SigType) | ||||
| 	binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) | ||||
| 	signed.Write(suffix) | ||||
| 	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: | ||||
| 		if err = rsa.VerifyPKCS1v15(pk.PublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { | ||||
| 			return errors.SignatureError("RSA verification failure") | ||||
| 		} | ||||
| 		return | ||||
| 	default: | ||||
| 		// V3 public keys only support RSA. | ||||
| 		panic("shouldn't happen") | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this | ||||
| // public key, that id is the identity of pub. | ||||
| func (pk *PublicKeyV3) VerifyUserIdSignatureV3(id string, pub *PublicKeyV3, sig *SignatureV3) (err error) { | ||||
| 	h, err := userIdSignatureV3Hash(id, pk, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignatureV3(h, sig) | ||||
| } | ||||
|  | ||||
| // VerifyKeySignatureV3 returns nil iff sig is a valid signature, made by this | ||||
| // public key, of signed. | ||||
| func (pk *PublicKeyV3) VerifyKeySignatureV3(signed *PublicKeyV3, sig *SignatureV3) (err error) { | ||||
| 	h, err := keySignatureHash(pk, signed, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return pk.VerifySignatureV3(h, sig) | ||||
| } | ||||
|  | ||||
| // userIdSignatureV3Hash returns a Hash of the message that needs to be signed | ||||
| // to assert that pk is a valid key for id. | ||||
| func userIdSignatureV3Hash(id string, pk signingKey, hfn crypto.Hash) (h hash.Hash, err error) { | ||||
| 	if !hfn.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash function") | ||||
| 	} | ||||
| 	h = hfn.New() | ||||
|  | ||||
| 	// RFC 4880, section 5.2.4 | ||||
| 	pk.SerializeSignaturePrefix(h) | ||||
| 	pk.serializeWithoutHeaders(h) | ||||
|  | ||||
| 	h.Write([]byte(id)) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // KeyIdString returns the public key's fingerprint in capital hex | ||||
| // (e.g. "6C7EE1B8621CC013"). | ||||
| func (pk *PublicKeyV3) KeyIdString() string { | ||||
| 	return fmt.Sprintf("%X", pk.KeyId) | ||||
| } | ||||
|  | ||||
| // KeyIdShortString returns the short form of public key's fingerprint | ||||
| // in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). | ||||
| func (pk *PublicKeyV3) KeyIdShortString() string { | ||||
| 	return fmt.Sprintf("%X", pk.KeyId&0xFFFFFFFF) | ||||
| } | ||||
|  | ||||
| // BitLength returns the bit length for the given public key. | ||||
| func (pk *PublicKeyV3) BitLength() (bitLength uint16, err error) { | ||||
| 	switch pk.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: | ||||
| 		bitLength = pk.n.bitLength | ||||
| 	default: | ||||
| 		err = errors.InvalidArgumentError("bad public-key algorithm") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										76
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| // 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/keybase/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 | ||||
| 		} | ||||
| 		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}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										880
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										880
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,880 @@ | ||||
| // 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/binary" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/s2k" | ||||
| 	"github.com/keybase/go-crypto/rsa" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// See RFC 4880, section 5.2.3.21 for details. | ||||
| 	KeyFlagCertify = 1 << iota | ||||
| 	KeyFlagSign | ||||
| 	KeyFlagEncryptCommunications | ||||
| 	KeyFlagEncryptStorage | ||||
| ) | ||||
|  | ||||
| // Signer can be implemented by application code to do actual signing. | ||||
| type Signer interface { | ||||
| 	hash.Hash | ||||
| 	Sign(sig *Signature) error | ||||
| 	KeyId() uint64 | ||||
| 	PublicKeyAlgo() PublicKeyAlgorithm | ||||
| } | ||||
|  | ||||
| // RevocationKey represents designated revoker packet. See RFC 4880 | ||||
| // section 5.2.3.15 for details. | ||||
| type RevocationKey struct { | ||||
| 	Class         byte | ||||
| 	PublicKeyAlgo PublicKeyAlgorithm | ||||
| 	Fingerprint   []byte | ||||
| } | ||||
|  | ||||
| // KeyFlagBits holds boolean whether any usage flags were provided in | ||||
| // the signature and BitField with KeyFlag* flags. | ||||
| type KeyFlagBits struct { | ||||
| 	Valid    bool | ||||
| 	BitField byte | ||||
| } | ||||
|  | ||||
| // Signature represents a signature. See RFC 4880, section 5.2. | ||||
| type Signature struct { | ||||
| 	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 | ||||
| 	CreationTime time.Time | ||||
|  | ||||
| 	RSASignature         parsedMPI | ||||
| 	DSASigR, DSASigS     parsedMPI | ||||
| 	ECDSASigR, ECDSASigS parsedMPI | ||||
| 	EdDSASigR, EdDSASigS parsedMPI | ||||
|  | ||||
| 	// 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 | ||||
| 	PreferredKeyServer                                      string | ||||
| 	IssuerKeyId                                             *uint64 | ||||
| 	IsPrimaryId                                             *bool | ||||
| 	IssuerFingerprint                                       []byte | ||||
|  | ||||
| 	// 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 | ||||
|  | ||||
| 	// PolicyURI is optional. See RFC 4880, Section 5.2.3.20 for details | ||||
| 	PolicyURI string | ||||
|  | ||||
| 	// Regex is a regex that can match a PGP UID. See RFC 4880, 5.2.3.14 for details | ||||
| 	Regex string | ||||
|  | ||||
| 	// MDC is set if this signature has a feature packet that indicates | ||||
| 	// support for MDC subpackets. | ||||
| 	MDC 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 | ||||
|  | ||||
| 	// StubbedOutCriticalError is not fail-stop, since it shouldn't break key parsing | ||||
| 	// when appearing in WoT-style cross signatures. But it should prevent a signature | ||||
| 	// from being applied to a primary or subkey. | ||||
| 	StubbedOutCriticalError error | ||||
|  | ||||
| 	// DesignaterRevoker will be present if this signature certifies a | ||||
| 	// designated revoking key id (3rd party key that can sign | ||||
| 	// revocation for this key). | ||||
| 	DesignatedRevoker *RevocationKey | ||||
|  | ||||
| 	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 { | ||||
| 		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, 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]) | ||||
| 	l := 6 + hashedSubpacketsLength | ||||
| 	sig.HashSuffix = make([]byte, l+6) | ||||
| 	sig.HashSuffix[0] = 4 | ||||
| 	copy(sig.HashSuffix[1:], buf[:5]) | ||||
| 	hashedSubpackets := sig.HashSuffix[6:l] | ||||
| 	_, err = readFull(r, hashedSubpackets) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	// See RFC 4880, section 5.2.4 | ||||
| 	trailer := sig.HashSuffix[l:] | ||||
| 	trailer[0] = 4 | ||||
| 	trailer[1] = 0xff | ||||
| 	trailer[2] = uint8(l >> 24) | ||||
| 	trailer[3] = uint8(l >> 16) | ||||
| 	trailer[4] = uint8(l >> 8) | ||||
| 	trailer[5] = uint8(l) | ||||
|  | ||||
| 	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.bytes, sig.RSASignature.bitLength, err = readMPI(r) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r) | ||||
| 		if err == nil { | ||||
| 			sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) | ||||
| 		} | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sig.EdDSASigR.bytes, sig.EdDSASigR.bitLength, err = readMPI(r) | ||||
| 		if err == nil { | ||||
| 			sig.EdDSASigS.bytes, sig.EdDSASigS.bitLength, err = readMPI(r) | ||||
| 		} | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r) | ||||
| 		if err == nil { | ||||
| 			sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r) | ||||
| 		} | ||||
| 	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 | ||||
| 	regularExpressionSubpacket   signatureSubpacketType = 6 | ||||
| 	keyExpirationSubpacket       signatureSubpacketType = 9 | ||||
| 	prefSymmetricAlgosSubpacket  signatureSubpacketType = 11 | ||||
| 	revocationKey                signatureSubpacketType = 12 | ||||
| 	issuerSubpacket              signatureSubpacketType = 16 | ||||
| 	prefHashAlgosSubpacket       signatureSubpacketType = 21 | ||||
| 	prefCompressionSubpacket     signatureSubpacketType = 22 | ||||
| 	prefKeyServerSubpacket       signatureSubpacketType = 24 | ||||
| 	primaryUserIdSubpacket       signatureSubpacketType = 25 | ||||
| 	policyURISubpacket           signatureSubpacketType = 26 | ||||
| 	keyFlagsSubpacket            signatureSubpacketType = 27 | ||||
| 	reasonForRevocationSubpacket signatureSubpacketType = 29 | ||||
| 	featuresSubpacket            signatureSubpacketType = 30 | ||||
| 	embeddedSignatureSubpacket   signatureSubpacketType = 32 | ||||
| 	issuerFingerprint            signatureSubpacketType = 33 | ||||
| ) | ||||
|  | ||||
| // 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: | ||||
| 		// 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. In practice, the subpacket is used exclusively to | ||||
| 		// indicate support for MDC-protected encryption. | ||||
| 		sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1 | ||||
| 	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: | ||||
| 		// See RFC 4880, Section 5.2.3.20 | ||||
| 		sig.PolicyURI = string(subpacket[:]) | ||||
| 	case regularExpressionSubpacket: | ||||
| 		sig.Regex = string(subpacket[:]) | ||||
| 		if isCritical { | ||||
| 			sig.StubbedOutCriticalError = errors.UnsupportedError("regex support is stubbed out") | ||||
| 		} | ||||
| 	case prefKeyServerSubpacket: | ||||
| 		sig.PreferredKeyServer = string(subpacket[:]) | ||||
| 	case issuerFingerprint: | ||||
| 		// The first byte is how many bytes the fingerprint is, but we'll just | ||||
| 		// read until the end of the subpacket, so we'll ignore it. | ||||
| 		sig.IssuerFingerprint = append([]byte{}, subpacket[1:]...) | ||||
| 	case revocationKey: | ||||
| 		// Authorizes the specified key to issue revocation signatures | ||||
| 		// for a key. | ||||
|  | ||||
| 		// TODO: Class octet must have bit 0x80 set. If the bit 0x40 | ||||
| 		// is set, then this means that the revocation information is | ||||
| 		// sensitive. | ||||
| 		sig.DesignatedRevoker = &RevocationKey{ | ||||
| 			Class:         subpacket[0], | ||||
| 			PublicKeyAlgo: PublicKeyAlgorithm(subpacket[1]), | ||||
| 			Fingerprint:   append([]byte{}, subpacket[2:]...), | ||||
| 		} | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| 			to = to[1+n:] | ||||
| 			n = copy(to, subpacket.contents) | ||||
| 			to = to[n:] | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // KeyExpired returns whether sig is a self-signature of a key that has | ||||
| // expired. | ||||
| func (sig *Signature) KeyExpired(currentTime time.Time) bool { | ||||
| 	if sig.KeyLifetimeSecs == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) | ||||
| 	return currentTime.After(expiry) | ||||
| } | ||||
|  | ||||
| // ExpiresBeforeOther checks if other signature has expiration at | ||||
| // later date than sig. | ||||
| func (sig *Signature) ExpiresBeforeOther(other *Signature) bool { | ||||
| 	if sig.KeyLifetimeSecs == nil { | ||||
| 		// This sig never expires, or has infinitely long expiration | ||||
| 		// time. | ||||
| 		return false | ||||
| 	} else if other.KeyLifetimeSecs == nil { | ||||
| 		// This sig expires at some non-infinite point, but the other | ||||
| 		// sig never expires. | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	getExpiryDate := func(s *Signature) time.Time { | ||||
| 		return s.CreationTime.Add(time.Duration(*s.KeyLifetimeSecs) * time.Second) | ||||
| 	} | ||||
|  | ||||
| 	return getExpiryDate(other).After(getExpiryDate(sig)) | ||||
| } | ||||
|  | ||||
| // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. | ||||
| func (sig *Signature) buildHashSuffix() (err error) { | ||||
| 	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) | ||||
|  | ||||
| 	var ok bool | ||||
| 	l := 6 + hashedSubpacketsLen | ||||
| 	sig.HashSuffix = make([]byte, l+6) | ||||
| 	sig.HashSuffix[0] = 4 | ||||
| 	sig.HashSuffix[1] = uint8(sig.SigType) | ||||
| 	sig.HashSuffix[2] = uint8(sig.PubKeyAlgo) | ||||
| 	sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash) | ||||
| 	if !ok { | ||||
| 		sig.HashSuffix = nil | ||||
| 		return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) | ||||
| 	} | ||||
| 	sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8) | ||||
| 	sig.HashSuffix[5] = byte(hashedSubpacketsLen) | ||||
| 	serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true) | ||||
| 	trailer := sig.HashSuffix[l:] | ||||
| 	trailer[0] = 4 | ||||
| 	trailer[1] = 0xff | ||||
| 	trailer[2] = byte(l >> 24) | ||||
| 	trailer[3] = byte(l >> 16) | ||||
| 	trailer[4] = byte(l >> 8) | ||||
| 	trailer[5] = byte(l) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { | ||||
| 	err = sig.buildHashSuffix() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	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) { | ||||
| 	signer, hashIsSigner := h.(Signer) | ||||
|  | ||||
| 	if !hashIsSigner && (priv == nil || priv.PrivateKey == nil) { | ||||
| 		err = errors.InvalidArgumentError("attempting to sign with nil PrivateKey") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	sig.outSubpackets = sig.buildSubpackets() | ||||
| 	digest, err := sig.signPrepareHash(h) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if hashIsSigner { | ||||
| 		err = signer.Sign(sig) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch priv.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest) | ||||
| 		sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) | ||||
| 	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.bytes = r.Bytes() | ||||
| 			sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) | ||||
| 			sig.DSASigS.bytes = s.Bytes() | ||||
| 			sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) | ||||
| 		} | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest) | ||||
| 		if err == nil { | ||||
| 			sig.ECDSASigR = FromBig(r) | ||||
| 			sig.ECDSASigS = FromBig(s) | ||||
| 		} | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		r, s, err := priv.PrivateKey.(*EdDSAPrivateKey).Sign(digest) | ||||
| 		if err == nil { | ||||
| 			sig.EdDSASigR = FromBytes(r) | ||||
| 			sig.EdDSASigS = FromBytes(s) | ||||
| 		} | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // 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 { | ||||
| 	h, err := userIdSignatureHash(id, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
|  | ||||
| // SignUserIdWithSigner 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) SignUserIdWithSigner(id string, pub *PublicKey, s Signer, config *Config) error { | ||||
| 	updateUserIdSignatureHash(id, pub, s) | ||||
|  | ||||
| 	return sig.Sign(s, nil, 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 { | ||||
| 	h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sig.Sign(h, priv, config) | ||||
| } | ||||
|  | ||||
| // SignKeyWithSigner computes a signature using s, asserting that | ||||
| // signeePubKey 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) SignKeyWithSigner(signeePubKey *PublicKey, signerPubKey *PublicKey, s Signer, config *Config) error { | ||||
| 	updateKeySignatureHash(signerPubKey, signeePubKey, s) | ||||
|  | ||||
| 	return sig.Sign(s, nil, 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.bytes == nil && | ||||
| 		sig.DSASigR.bytes == nil && | ||||
| 		sig.ECDSASigR.bytes == nil && | ||||
| 		sig.EdDSASigR.bytes == nil { | ||||
| 		return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | ||||
| 	} | ||||
|  | ||||
| 	sigLength := 0 | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		sigLength = 2 + len(sig.RSASignature.bytes) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		sigLength = 2 + len(sig.DSASigR.bytes) | ||||
| 		sigLength += 2 + len(sig.DSASigS.bytes) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		sigLength = 2 + len(sig.EdDSASigR.bytes) | ||||
| 		sigLength += 2 + len(sig.EdDSASigS.bytes) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		sigLength = 2 + len(sig.ECDSASigR.bytes) | ||||
| 		sigLength += 2 + len(sig.ECDSASigS.bytes) | ||||
| 	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 | ||||
| 	err = serializeHeader(w, packetTypeSignature, length) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	_, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	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 = writeMPIs(w, sig.RSASignature) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		err = writeMPIs(w, sig.DSASigR, sig.DSASigS) | ||||
| 	case PubKeyAlgoEdDSA: | ||||
| 		err = writeMPIs(w, sig.EdDSASigR, sig.EdDSASigS) | ||||
| 	case PubKeyAlgoECDSA: | ||||
| 		err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS) | ||||
| 	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() (subpackets []outputSubpacket) { | ||||
| 	creationTime := make([]byte, 4) | ||||
| 	binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) | ||||
| 	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) | ||||
|  | ||||
| 	if sig.IssuerKeyId != nil { | ||||
| 		keyId := make([]byte, 8) | ||||
| 		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId}) | ||||
| 	} | ||||
|  | ||||
| 	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 { | ||||
| 		subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{sig.GetKeyFlags().BitField}}) | ||||
| 	} | ||||
|  | ||||
| 	// The following subpackets may only appear in self-signatures | ||||
|  | ||||
| 	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}) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (sig *Signature) GetKeyFlags() (ret KeyFlagBits) { | ||||
| 	if !sig.FlagsValid { | ||||
| 		return ret | ||||
| 	} | ||||
|  | ||||
| 	ret.Valid = true | ||||
| 	if sig.FlagCertify { | ||||
| 		ret.BitField |= KeyFlagCertify | ||||
| 	} | ||||
| 	if sig.FlagSign { | ||||
| 		ret.BitField |= KeyFlagSign | ||||
| 	} | ||||
| 	if sig.FlagEncryptCommunications { | ||||
| 		ret.BitField |= KeyFlagEncryptCommunications | ||||
| 	} | ||||
| 	if sig.FlagEncryptStorage { | ||||
| 		ret.BitField |= KeyFlagEncryptStorage | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| func (f *KeyFlagBits) HasFlagCertify() bool { | ||||
| 	return f.BitField&KeyFlagCertify != 0 | ||||
| } | ||||
|  | ||||
| func (f *KeyFlagBits) HasFlagSign() bool { | ||||
| 	return f.BitField&KeyFlagSign != 0 | ||||
| } | ||||
|  | ||||
| func (f *KeyFlagBits) HasFlagEncryptCommunications() bool { | ||||
| 	return f.BitField&KeyFlagEncryptCommunications != 0 | ||||
| } | ||||
|  | ||||
| func (f *KeyFlagBits) HasFlagEncryptStorage() bool { | ||||
| 	return f.BitField&KeyFlagEncryptStorage != 0 | ||||
| } | ||||
|  | ||||
| func (f *KeyFlagBits) Merge(other KeyFlagBits) { | ||||
| 	if other.Valid { | ||||
| 		f.Valid = true | ||||
| 		f.BitField |= other.BitField | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										146
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/signature_v3.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/signature_v3.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| // 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 ( | ||||
| 	"crypto" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/s2k" | ||||
| ) | ||||
|  | ||||
| // SignatureV3 represents older version 3 signatures. These signatures are less secure | ||||
| // than version 4 and should not be used to create new signatures. They are included | ||||
| // here for backwards compatibility to read and validate with older key material. | ||||
| // See RFC 4880, section 5.2.2. | ||||
| type SignatureV3 struct { | ||||
| 	SigType      SignatureType | ||||
| 	CreationTime time.Time | ||||
| 	IssuerKeyId  uint64 | ||||
| 	PubKeyAlgo   PublicKeyAlgorithm | ||||
| 	Hash         crypto.Hash | ||||
| 	HashTag      [2]byte | ||||
|  | ||||
| 	RSASignature     parsedMPI | ||||
| 	DSASigR, DSASigS parsedMPI | ||||
| } | ||||
|  | ||||
| func (sig *SignatureV3) parse(r io.Reader) (err error) { | ||||
| 	// RFC 4880, section 5.2.2 | ||||
| 	var buf [8]byte | ||||
| 	if _, err = readFull(r, buf[:1]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] < 2 || buf[0] > 3 { | ||||
| 		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) | ||||
| 		return | ||||
| 	} | ||||
| 	if _, err = readFull(r, buf[:1]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if buf[0] != 5 { | ||||
| 		err = errors.UnsupportedError( | ||||
| 			"invalid hashed material length " + strconv.Itoa(int(buf[0]))) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Read hashed material: signature type + creation time | ||||
| 	if _, err = readFull(r, buf[:5]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sig.SigType = SignatureType(buf[0]) | ||||
| 	t := binary.BigEndian.Uint32(buf[1:5]) | ||||
| 	sig.CreationTime = time.Unix(int64(t), 0) | ||||
|  | ||||
| 	// Eight-octet Key ID of signer. | ||||
| 	if _, err = readFull(r, buf[:8]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:]) | ||||
|  | ||||
| 	// Public-key and hash algorithm | ||||
| 	if _, err = readFull(r, buf[:2]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0]) | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA: | ||||
| 	default: | ||||
| 		err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) | ||||
| 		return | ||||
| 	} | ||||
| 	var ok bool | ||||
| 	if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok { | ||||
| 		return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) | ||||
| 	} | ||||
|  | ||||
| 	// Two-octet field holding left 16 bits of signed hash value. | ||||
| 	if _, err = readFull(r, sig.HashTag[:2]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) | ||||
| 	default: | ||||
| 		panic("unreachable") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been | ||||
| // called first. | ||||
| func (sig *SignatureV3) Serialize(w io.Writer) (err error) { | ||||
| 	buf := make([]byte, 8) | ||||
|  | ||||
| 	// Write the sig type and creation time | ||||
| 	buf[0] = byte(sig.SigType) | ||||
| 	binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix())) | ||||
| 	if _, err = w.Write(buf[:5]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Write the issuer long key ID | ||||
| 	binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId) | ||||
| 	if _, err = w.Write(buf[:8]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Write public key algorithm, hash ID, and hash value | ||||
| 	buf[0] = byte(sig.PubKeyAlgo) | ||||
| 	hashId, ok := s2k.HashToHashId(sig.Hash) | ||||
| 	if !ok { | ||||
| 		return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash)) | ||||
| 	} | ||||
| 	buf[1] = hashId | ||||
| 	copy(buf[2:4], sig.HashTag[:]) | ||||
| 	if _, err = w.Write(buf[:4]); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil { | ||||
| 		return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") | ||||
| 	} | ||||
|  | ||||
| 	switch sig.PubKeyAlgo { | ||||
| 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: | ||||
| 		err = writeMPIs(w, sig.RSASignature) | ||||
| 	case PubKeyAlgoDSA: | ||||
| 		err = writeMPIs(w, sig.DSASigR, sig.DSASigS) | ||||
| 	default: | ||||
| 		panic("impossible") | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										158
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/symmetric_key_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/symmetric_key_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | ||||
| // 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/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/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 { | ||||
| 	CipherFunc   CipherFunction | ||||
| 	s2k          func(out, in []byte) | ||||
| 	encryptedKey []byte | ||||
| } | ||||
|  | ||||
| const symmetricKeyEncryptedVersion = 4 | ||||
|  | ||||
| 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 | ||||
| 	} | ||||
| 	if buf[0] != symmetricKeyEncryptedVersion { | ||||
| 		return errors.UnsupportedError("SymmetricKeyEncrypted version") | ||||
| 	} | ||||
| 	ske.CipherFunc = CipherFunction(buf[1]) | ||||
|  | ||||
| 	if ske.CipherFunc.KeySize() == 0 { | ||||
| 		return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	ske.s2k, err = s2k.Parse(r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if ske.s2k == nil { | ||||
| 		return errors.UnsupportedError("can't use dummy S2K for symmetric key encryption") | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 	// 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 l := len(plaintextKey); l == 0 || l%cipherFunc.blockSize() != 0 { | ||||
| 		return nil, cipherFunc, errors.StructuralError("length of decrypted key not a multiple of block size") | ||||
| 	} | ||||
|  | ||||
| 	return plaintextKey, cipherFunc, 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. | ||||
| // 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))) | ||||
| 	} | ||||
|  | ||||
| 	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() | ||||
|  | ||||
| 	packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize | ||||
| 	err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var buf [2]byte | ||||
| 	buf[0] = symmetricKeyEncryptedVersion | ||||
| 	buf[1] = byte(cipherFunc) | ||||
| 	_, err = w.Write(buf[:]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	_, err = w.Write(s2kBytes) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	sessionKey := make([]byte, keySize) | ||||
| 	_, err = io.ReadFull(config.Random(), sessionKey) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 	key = sessionKey | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										291
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/symmetrically_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/symmetrically_encrypted.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,291 @@ | ||||
| // 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/keybase/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 can, with high probability, be detected | ||||
| // immediately and this will result in a KeyIncorrect error being returned. | ||||
| 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) | ||||
| 	if s == nil { | ||||
| 		return nil, errors.ErrKeyIncorrect | ||||
| 	} | ||||
|  | ||||
| 	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.SignatureError("error during reading") | ||||
| 	} | ||||
|  | ||||
| 	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.SignatureError("error during reading") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { | ||||
| 		return errors.SignatureError("MDC packet not found") | ||||
| 	} | ||||
| 	ser.h.Write(ser.trailer[:2]) | ||||
|  | ||||
| 	final := ser.h.Sum(nil) | ||||
| 	if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { | ||||
| 		return errors.SignatureError("hash mismatch") | ||||
| 	} | ||||
| 	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 | ||||
| } | ||||
							
								
								
									
										91
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/userattribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/github.com/keybase/go-crypto/openpgp/packet/userattribute.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| // 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 { | ||||
| 		sp.Serialize(&buf) | ||||
| 	} | ||||
| 	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 | ||||
| // 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/keybase/go-crypto/openpgp/packet/userid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/keybase/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 | ||||
| } | ||||
							
								
								
									
										7
									
								
								vendor/github.com/keybase/go-crypto/openpgp/patch.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/keybase/go-crypto/openpgp/patch.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| patch < sig-v3.patch | ||||
| patch < s2k-gnu-dummy.patch | ||||
| find . -type f -name '*.go' -exec sed -i'' -e 's/golang.org\/x\/crypto\/openpgp/github.com\/keybase\/go-crypto\/openpgp/' {} \; | ||||
| find . -type f -name '*.go-e' -exec rm {} \; | ||||
| go test ./... | ||||
							
								
								
									
										463
									
								
								vendor/github.com/keybase/go-crypto/openpgp/read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										463
									
								
								vendor/github.com/keybase/go-crypto/openpgp/read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,463 @@ | ||||
| // Copyright 2011 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package openpgp implements high level operations on OpenPGP messages. | ||||
| package openpgp // import "github.com/keybase/go-crypto/openpgp" | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"crypto/hmac" | ||||
| 	_ "crypto/sha256" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/armor" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/packet" | ||||
| ) | ||||
|  | ||||
| // SignatureType is the armor type for a PGP signature. | ||||
| var SignatureType = "PGP SIGNATURE" | ||||
|  | ||||
| // readArmored reads an armored block with the given type. | ||||
| func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) { | ||||
| 	block, err := armor.Decode(r) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if block.Type != expectedType { | ||||
| 		return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type) | ||||
| 	} | ||||
|  | ||||
| 	return block.Body, nil | ||||
| } | ||||
|  | ||||
| // MessageDetails contains the result of parsing an OpenPGP encrypted and/or | ||||
| // signed message. | ||||
| type MessageDetails struct { | ||||
| 	IsEncrypted              bool                // true if the message was encrypted. | ||||
| 	EncryptedToKeyIds        []uint64            // the list of recipient key ids. | ||||
| 	IsSymmetricallyEncrypted bool                // true if a passphrase could have decrypted the message. | ||||
| 	DecryptedWith            Key                 // the private key used to decrypt the message, if any. | ||||
| 	IsSigned                 bool                // true if the message is signed. | ||||
| 	SignedByKeyId            uint64              // the key id of the signer, if any. | ||||
| 	SignedBy                 *Key                // the key of the signer, if available. | ||||
| 	LiteralData              *packet.LiteralData // the metadata of the contents | ||||
| 	UnverifiedBody           io.Reader           // the contents of the message. | ||||
|  | ||||
| 	// If IsSigned is true and SignedBy is non-zero then the signature will | ||||
| 	// be verified as UnverifiedBody is read. The signature cannot be | ||||
| 	// checked until the whole of UnverifiedBody is read so UnverifiedBody | ||||
| 	// must be consumed until EOF before the data can trusted. Even if a | ||||
| 	// message isn't signed (or the signer is unknown) the data may contain | ||||
| 	// an authentication code that is only checked once UnverifiedBody has | ||||
| 	// been consumed. Once EOF has been seen, the following fields are | ||||
| 	// valid. (An authentication code failure is reported as a | ||||
| 	// SignatureError error when reading from UnverifiedBody.) | ||||
| 	SignatureError error               // nil if the signature is good. | ||||
| 	Signature      *packet.Signature   // the signature packet itself, if v4 (default) | ||||
| 	SignatureV3    *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature | ||||
|  | ||||
| 	decrypted io.ReadCloser | ||||
| } | ||||
|  | ||||
| // A PromptFunction is used as a callback by functions that may need to decrypt | ||||
| // a private key, or prompt for a passphrase. It is called with a list of | ||||
| // acceptable, encrypted private keys and a boolean that indicates whether a | ||||
| // passphrase is usable. It should either decrypt a private key or return a | ||||
| // passphrase to try. If the decrypted private key or given passphrase isn't | ||||
| // correct, the function will be called again, forever. Any error returned will | ||||
| // be passed up. | ||||
| type PromptFunction func(keys []Key, symmetric bool) ([]byte, error) | ||||
|  | ||||
| // A keyEnvelopePair is used to store a private key with the envelope that | ||||
| // contains a symmetric key, encrypted with that key. | ||||
| type keyEnvelopePair struct { | ||||
| 	key          Key | ||||
| 	encryptedKey *packet.EncryptedKey | ||||
| } | ||||
|  | ||||
| // ReadMessage parses an OpenPGP message that may be signed and/or encrypted. | ||||
| // The given KeyRing should contain both public keys (for signature | ||||
| // verification) and, possibly encrypted, private keys for decrypting. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) { | ||||
| 	var p packet.Packet | ||||
|  | ||||
| 	var symKeys []*packet.SymmetricKeyEncrypted | ||||
| 	var pubKeys []keyEnvelopePair | ||||
| 	var se *packet.SymmetricallyEncrypted | ||||
|  | ||||
| 	packets := packet.NewReader(r) | ||||
| 	md = new(MessageDetails) | ||||
| 	md.IsEncrypted = true | ||||
|  | ||||
| 	// The message, if encrypted, starts with a number of packets | ||||
| 	// containing an encrypted decryption key. The decryption key is either | ||||
| 	// encrypted to a public key, or with a passphrase. This loop | ||||
| 	// collects these packets. | ||||
| ParsePackets: | ||||
| 	for { | ||||
| 		p, err = packets.Next() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		switch p := p.(type) { | ||||
| 		case *packet.SymmetricKeyEncrypted: | ||||
| 			// This packet contains the decryption key encrypted with a passphrase. | ||||
| 			md.IsSymmetricallyEncrypted = true | ||||
| 			symKeys = append(symKeys, p) | ||||
| 		case *packet.EncryptedKey: | ||||
| 			// This packet contains the decryption key encrypted to a public key. | ||||
| 			md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) | ||||
| 			switch p.Algo { | ||||
| 			case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH: | ||||
| 				break | ||||
| 			default: | ||||
| 				continue | ||||
| 			} | ||||
| 			var keys []Key | ||||
| 			if p.KeyId == 0 { | ||||
| 				keys = keyring.DecryptionKeys() | ||||
| 			} else { | ||||
| 				keys = keyring.KeysById(p.KeyId, nil) | ||||
| 			} | ||||
| 			for _, k := range keys { | ||||
| 				pubKeys = append(pubKeys, keyEnvelopePair{k, p}) | ||||
| 			} | ||||
| 		case *packet.SymmetricallyEncrypted: | ||||
| 			se = p | ||||
| 			break ParsePackets | ||||
| 		case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: | ||||
| 			// This message isn't encrypted. | ||||
| 			if len(symKeys) != 0 || len(pubKeys) != 0 { | ||||
| 				return nil, errors.StructuralError("key material not followed by encrypted message") | ||||
| 			} | ||||
| 			packets.Unread(p) | ||||
| 			return readSignedMessage(packets, nil, keyring) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var candidates []Key | ||||
| 	var decrypted io.ReadCloser | ||||
|  | ||||
| 	// Now that we have the list of encrypted keys we need to decrypt at | ||||
| 	// least one of them or, if we cannot, we need to call the prompt | ||||
| 	// function so that it can decrypt a key or give us a passphrase. | ||||
| FindKey: | ||||
| 	for { | ||||
| 		// See if any of the keys already have a private key available | ||||
| 		candidates = candidates[:0] | ||||
| 		candidateFingerprints := make(map[string]bool) | ||||
|  | ||||
| 		for _, pk := range pubKeys { | ||||
| 			if pk.key.PrivateKey == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			if !pk.key.PrivateKey.Encrypted { | ||||
| 				if len(pk.encryptedKey.Key) == 0 { | ||||
| 					pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) | ||||
| 				} | ||||
| 				if len(pk.encryptedKey.Key) == 0 { | ||||
| 					continue | ||||
| 				} | ||||
| 				decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) | ||||
| 				if err != nil && err != errors.ErrKeyIncorrect { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				if decrypted != nil { | ||||
| 					md.DecryptedWith = pk.key | ||||
| 					break FindKey | ||||
| 				} | ||||
| 			} else { | ||||
| 				fpr := string(pk.key.PublicKey.Fingerprint[:]) | ||||
| 				if v := candidateFingerprints[fpr]; v { | ||||
| 					continue | ||||
| 				} | ||||
| 				candidates = append(candidates, pk.key) | ||||
| 				candidateFingerprints[fpr] = true | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if len(candidates) == 0 && len(symKeys) == 0 { | ||||
| 			return nil, errors.ErrKeyIncorrect | ||||
| 		} | ||||
|  | ||||
| 		if prompt == nil { | ||||
| 			return nil, errors.ErrKeyIncorrect | ||||
| 		} | ||||
|  | ||||
| 		passphrase, err := prompt(candidates, len(symKeys) != 0) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		// Try the symmetric passphrase first | ||||
| 		if len(symKeys) != 0 && passphrase != nil { | ||||
| 			for _, s := range symKeys { | ||||
| 				key, cipherFunc, err := s.Decrypt(passphrase) | ||||
| 				if err == nil { | ||||
| 					decrypted, err = se.Decrypt(cipherFunc, key) | ||||
| 					if err != nil && err != errors.ErrKeyIncorrect { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 					if decrypted != nil { | ||||
| 						break FindKey | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	md.decrypted = decrypted | ||||
| 	if err := packets.Push(decrypted); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return readSignedMessage(packets, md, keyring) | ||||
| } | ||||
|  | ||||
| // readSignedMessage reads a possibly signed message if mdin is non-zero then | ||||
| // that structure is updated and returned. Otherwise a fresh MessageDetails is | ||||
| // used. | ||||
| func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) { | ||||
| 	if mdin == nil { | ||||
| 		mdin = new(MessageDetails) | ||||
| 	} | ||||
| 	md = mdin | ||||
|  | ||||
| 	var p packet.Packet | ||||
| 	var h hash.Hash | ||||
| 	var wrappedHash hash.Hash | ||||
| FindLiteralData: | ||||
| 	for { | ||||
| 		p, err = packets.Next() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		switch p := p.(type) { | ||||
| 		case *packet.Compressed: | ||||
| 			if err := packets.Push(p.Body); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		case *packet.OnePassSignature: | ||||
| 			if !p.IsLast { | ||||
| 				return nil, errors.UnsupportedError("nested signatures") | ||||
| 			} | ||||
|  | ||||
| 			h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) | ||||
| 			if err != nil { | ||||
| 				md = nil | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			md.IsSigned = true | ||||
| 			md.SignedByKeyId = p.KeyId | ||||
| 			keys := keyring.KeysByIdUsage(p.KeyId, nil, packet.KeyFlagSign) | ||||
| 			if len(keys) > 0 { | ||||
| 				md.SignedBy = &keys[0] | ||||
| 			} | ||||
| 		case *packet.LiteralData: | ||||
| 			md.LiteralData = p | ||||
| 			break FindLiteralData | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if md.SignedBy != nil { | ||||
| 		md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md} | ||||
| 	} else if md.decrypted != nil { | ||||
| 		md.UnverifiedBody = checkReader{md} | ||||
| 	} else { | ||||
| 		md.UnverifiedBody = md.LiteralData.Body | ||||
| 	} | ||||
|  | ||||
| 	return md, nil | ||||
| } | ||||
|  | ||||
| // hashForSignature returns a pair of hashes that can be used to verify a | ||||
| // signature. The signature may specify that the contents of the signed message | ||||
| // should be preprocessed (i.e. to normalize line endings). Thus this function | ||||
| // returns two hashes. The second should be used to hash the message itself and | ||||
| // performs any needed preprocessing. | ||||
| func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { | ||||
| 	if !hashId.Available() { | ||||
| 		return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) | ||||
| 	} | ||||
| 	h := hashId.New() | ||||
|  | ||||
| 	switch sigType { | ||||
| 	case packet.SigTypeBinary: | ||||
| 		return h, h, nil | ||||
| 	case packet.SigTypeText: | ||||
| 		return h, NewCanonicalTextHash(h), nil | ||||
| 	} | ||||
|  | ||||
| 	return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType))) | ||||
| } | ||||
|  | ||||
| // checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF | ||||
| // it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger | ||||
| // MDC checks. | ||||
| type checkReader struct { | ||||
| 	md *MessageDetails | ||||
| } | ||||
|  | ||||
| func (cr checkReader) Read(buf []byte) (n int, err error) { | ||||
| 	n, err = cr.md.LiteralData.Body.Read(buf) | ||||
| 	if err == io.EOF { | ||||
| 		mdcErr := cr.md.decrypted.Close() | ||||
| 		if mdcErr != nil { | ||||
| 			err = mdcErr | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes | ||||
| // the data as it is read. When it sees an EOF from the underlying io.Reader | ||||
| // it parses and checks a trailing Signature packet and triggers any MDC checks. | ||||
| type signatureCheckReader struct { | ||||
| 	packets        *packet.Reader | ||||
| 	h, wrappedHash hash.Hash | ||||
| 	md             *MessageDetails | ||||
| } | ||||
|  | ||||
| func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { | ||||
| 	n, err = scr.md.LiteralData.Body.Read(buf) | ||||
| 	scr.wrappedHash.Write(buf[:n]) | ||||
| 	if err == io.EOF { | ||||
| 		var p packet.Packet | ||||
| 		p, scr.md.SignatureError = scr.packets.Next() | ||||
| 		if scr.md.SignatureError != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		var ok bool | ||||
| 		if scr.md.Signature, ok = p.(*packet.Signature); ok { | ||||
| 			var err error | ||||
| 			if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil { | ||||
| 				if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) { | ||||
| 					err = errors.StructuralError("bad key fingerprint") | ||||
| 				} | ||||
| 			} | ||||
| 			if err == nil { | ||||
| 				err = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | ||||
| 			} | ||||
| 			scr.md.SignatureError = err | ||||
| 		} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { | ||||
| 			scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) | ||||
| 		} else { | ||||
| 			scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// The SymmetricallyEncrypted packet, if any, might have an | ||||
| 		// unsigned hash of its own. In order to check this we need to | ||||
| 		// close that Reader. | ||||
| 		if scr.md.decrypted != nil { | ||||
| 			mdcErr := scr.md.decrypted.Close() | ||||
| 			if mdcErr != nil { | ||||
| 				err = mdcErr | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // CheckDetachedSignature takes a signed file and a detached signature and | ||||
| // returns the signer if the signature is valid. If the signer isn't known, | ||||
| // ErrUnknownIssuer is returned. | ||||
| func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { | ||||
| 	signer, _, err = checkDetachedSignature(keyring, signed, signature) | ||||
| 	return signer, err | ||||
| } | ||||
|  | ||||
| func checkDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, issuer *uint64, err error) { | ||||
| 	var issuerKeyId uint64 | ||||
| 	var issuerFingerprint []byte | ||||
| 	var hashFunc crypto.Hash | ||||
| 	var sigType packet.SignatureType | ||||
| 	var keys []Key | ||||
| 	var p packet.Packet | ||||
|  | ||||
| 	packets := packet.NewReader(signature) | ||||
| 	for { | ||||
| 		p, err = packets.Next() | ||||
| 		if err == io.EOF { | ||||
| 			return nil, nil, errors.ErrUnknownIssuer | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
|  | ||||
| 		switch sig := p.(type) { | ||||
| 		case *packet.Signature: | ||||
| 			if sig.IssuerKeyId == nil { | ||||
| 				return nil, nil, errors.StructuralError("signature doesn't have an issuer") | ||||
| 			} | ||||
| 			issuerKeyId = *sig.IssuerKeyId | ||||
| 			hashFunc = sig.Hash | ||||
| 			sigType = sig.SigType | ||||
| 			issuerFingerprint = sig.IssuerFingerprint | ||||
| 		case *packet.SignatureV3: | ||||
| 			issuerKeyId = sig.IssuerKeyId | ||||
| 			hashFunc = sig.Hash | ||||
| 			sigType = sig.SigType | ||||
| 		default: | ||||
| 			return nil, nil, errors.StructuralError("non signature packet found") | ||||
| 		} | ||||
|  | ||||
| 		keys = keyring.KeysByIdUsage(issuerKeyId, issuerFingerprint, packet.KeyFlagSign) | ||||
| 		if len(keys) > 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(keys) == 0 { | ||||
| 		panic("unreachable") | ||||
| 	} | ||||
|  | ||||
| 	h, wrappedHash, err := hashForSignature(hashFunc, sigType) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	for _, key := range keys { | ||||
| 		switch sig := p.(type) { | ||||
| 		case *packet.Signature: | ||||
| 			err = key.PublicKey.VerifySignature(h, sig) | ||||
| 		case *packet.SignatureV3: | ||||
| 			err = key.PublicKey.VerifySignatureV3(h, sig) | ||||
| 		default: | ||||
| 			panic("unreachable") | ||||
| 		} | ||||
|  | ||||
| 		if err == nil { | ||||
| 			return key.Entity, &issuerKeyId, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil, nil, err | ||||
| } | ||||
|  | ||||
| // CheckArmoredDetachedSignature performs the same actions as | ||||
| // CheckDetachedSignature but expects the signature to be armored. | ||||
| func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { | ||||
| 	signer, _, err = checkArmoredDetachedSignature(keyring, signed, signature) | ||||
| 	return signer, err | ||||
| } | ||||
|  | ||||
| func checkArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, issuer *uint64, err error) { | ||||
| 	body, err := readArmored(signature, SignatureType) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return checkDetachedSignature(keyring, signed, body) | ||||
| } | ||||
							
								
								
									
										326
									
								
								vendor/github.com/keybase/go-crypto/openpgp/s2k/s2k.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								vendor/github.com/keybase/go-crypto/openpgp/s2k/s2k.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,326 @@ | ||||
| // 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 s2k implements the various OpenPGP string-to-key transforms as | ||||
| // specified in RFC 4800 section 3.7.1. | ||||
| package s2k // import "github.com/keybase/go-crypto/openpgp/s2k" | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| ) | ||||
|  | ||||
| // Config collects configuration parameters for s2k key-stretching | ||||
| // transformatioms. A nil *Config is valid and results in all default | ||||
| // values. Currently, Config is used only by the Serialize function in | ||||
| // this package. | ||||
| type Config struct { | ||||
| 	// Hash is the default hash function to be used. If | ||||
| 	// nil, SHA1 is used. | ||||
| 	Hash crypto.Hash | ||||
| 	// 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 | ||||
| } | ||||
|  | ||||
| func (c *Config) hash() crypto.Hash { | ||||
| 	if c == nil || uint(c.Hash) == 0 { | ||||
| 		// SHA1 is the historical default in this package. | ||||
| 		return crypto.SHA1 | ||||
| 	} | ||||
|  | ||||
| 	return c.Hash | ||||
| } | ||||
|  | ||||
| func (c *Config) encodedCount() uint8 { | ||||
| 	if c == nil || c.S2KCount == 0 { | ||||
| 		return 96 // The common case. Correspoding to 65536 | ||||
| 	} | ||||
|  | ||||
| 	i := c.S2KCount | ||||
| 	switch { | ||||
| 	// Behave like GPG. Should we make 65536 the lowest value used? | ||||
| 	case i < 1024: | ||||
| 		i = 1024 | ||||
| 	case i > 65011712: | ||||
| 		i = 65011712 | ||||
| 	} | ||||
|  | ||||
| 	return encodeCount(i) | ||||
| } | ||||
|  | ||||
| // encodeCount converts an iterative "count" in the range 1024 to | ||||
| // 65011712, inclusive, to an encoded count. The return value is the | ||||
| // octet that is actually stored in the GPG file. encodeCount panics | ||||
| // if i is not in the above range (encodedCount above takes care to | ||||
| // pass i in the correct range). See RFC 4880 Section 3.7.7.1. | ||||
| func encodeCount(i int) uint8 { | ||||
| 	if i < 1024 || i > 65011712 { | ||||
| 		panic("count arg i outside the required range") | ||||
| 	} | ||||
|  | ||||
| 	for encoded := 0; encoded < 256; encoded++ { | ||||
| 		count := decodeCount(uint8(encoded)) | ||||
| 		if count >= i { | ||||
| 			return uint8(encoded) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 255 | ||||
| } | ||||
|  | ||||
| // decodeCount returns the s2k mode 3 iterative "count" corresponding to | ||||
| // the encoded octet c. | ||||
| func decodeCount(c uint8) int { | ||||
| 	return (16 + int(c&15)) << (uint32(c>>4) + 6) | ||||
| } | ||||
|  | ||||
| // Simple writes to out the result of computing the Simple S2K function (RFC | ||||
| // 4880, section 3.7.1.1) using the given hash and input passphrase. | ||||
| func Simple(out []byte, h hash.Hash, in []byte) { | ||||
| 	Salted(out, h, in, nil) | ||||
| } | ||||
|  | ||||
| var zero [1]byte | ||||
|  | ||||
| // Salted writes to out the result of computing the Salted S2K function (RFC | ||||
| // 4880, section 3.7.1.2) using the given hash, input passphrase and salt. | ||||
| func Salted(out []byte, h hash.Hash, in []byte, salt []byte) { | ||||
| 	done := 0 | ||||
| 	var digest []byte | ||||
|  | ||||
| 	for i := 0; done < len(out); i++ { | ||||
| 		h.Reset() | ||||
| 		for j := 0; j < i; j++ { | ||||
| 			h.Write(zero[:]) | ||||
| 		} | ||||
| 		h.Write(salt) | ||||
| 		h.Write(in) | ||||
| 		digest = h.Sum(digest[:0]) | ||||
| 		n := copy(out[done:], digest) | ||||
| 		done += n | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Iterated writes to out the result of computing the Iterated and Salted S2K | ||||
| // function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase, | ||||
| // salt and iteration count. | ||||
| func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { | ||||
| 	combined := make([]byte, len(in)+len(salt)) | ||||
| 	copy(combined, salt) | ||||
| 	copy(combined[len(salt):], in) | ||||
|  | ||||
| 	if count < len(combined) { | ||||
| 		count = len(combined) | ||||
| 	} | ||||
|  | ||||
| 	done := 0 | ||||
| 	var digest []byte | ||||
| 	for i := 0; done < len(out); i++ { | ||||
| 		h.Reset() | ||||
| 		for j := 0; j < i; j++ { | ||||
| 			h.Write(zero[:]) | ||||
| 		} | ||||
| 		written := 0 | ||||
| 		for written < count { | ||||
| 			if written+len(combined) > count { | ||||
| 				todo := count - written | ||||
| 				h.Write(combined[:todo]) | ||||
| 				written = count | ||||
| 			} else { | ||||
| 				h.Write(combined) | ||||
| 				written += len(combined) | ||||
| 			} | ||||
| 		} | ||||
| 		digest = h.Sum(digest[:0]) | ||||
| 		n := copy(out[done:], digest) | ||||
| 		done += n | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func parseGNUExtensions(r io.Reader) (f func(out, in []byte), err error) { | ||||
| 	var buf [9]byte | ||||
|  | ||||
| 	// A three-byte string identifier | ||||
| 	_, err = io.ReadFull(r, buf[:3]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	gnuExt := string(buf[:3]) | ||||
|  | ||||
| 	if gnuExt != "GNU" { | ||||
| 		return nil, errors.UnsupportedError("Malformed GNU extension: " + gnuExt) | ||||
| 	} | ||||
| 	_, err = io.ReadFull(r, buf[:1]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	gnuExtType := int(buf[0]) | ||||
| 	switch gnuExtType { | ||||
| 	case 1: | ||||
| 		return nil, nil | ||||
| 	case 2: | ||||
| 		// Read a serial number, which is prefixed by a 1-byte length. | ||||
| 		// The maximum length is 16. | ||||
| 		var lenBuf [1]byte | ||||
| 		_, err = io.ReadFull(r, lenBuf[:]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		maxLen := 16 | ||||
| 		ivLen := int(lenBuf[0]) | ||||
| 		if ivLen > maxLen { | ||||
| 			ivLen = maxLen | ||||
| 		} | ||||
| 		ivBuf := make([]byte, ivLen) | ||||
| 		// For now we simply discard the IV | ||||
| 		_, err = io.ReadFull(r, ivBuf) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		return nil, nil | ||||
| 	default: | ||||
| 		return nil, errors.UnsupportedError("unknown S2K GNU protection mode: " + strconv.Itoa(int(gnuExtType))) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Parse reads a binary specification for a string-to-key transformation from r | ||||
| // and returns a function which performs that transform. | ||||
| func Parse(r io.Reader) (f func(out, in []byte), err error) { | ||||
| 	var buf [9]byte | ||||
|  | ||||
| 	_, err = io.ReadFull(r, buf[:2]) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// GNU Extensions; handle them before we try to look for a hash, which won't | ||||
| 	// be needed in most cases anyway. | ||||
| 	if buf[0] == 101 { | ||||
| 		return parseGNUExtensions(r) | ||||
| 	} | ||||
|  | ||||
| 	hash, ok := HashIdToHash(buf[1]) | ||||
| 	if !ok { | ||||
| 		return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1]))) | ||||
| 	} | ||||
| 	if !hash.Available() { | ||||
| 		return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash))) | ||||
| 	} | ||||
| 	h := hash.New() | ||||
|  | ||||
| 	switch buf[0] { | ||||
| 	case 0: | ||||
| 		f := func(out, in []byte) { | ||||
| 			Simple(out, h, in) | ||||
| 		} | ||||
| 		return f, nil | ||||
| 	case 1: | ||||
| 		_, err = io.ReadFull(r, buf[:8]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		f := func(out, in []byte) { | ||||
| 			Salted(out, h, in, buf[:8]) | ||||
| 		} | ||||
| 		return f, nil | ||||
| 	case 3: | ||||
| 		_, err = io.ReadFull(r, buf[:9]) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		count := decodeCount(buf[8]) | ||||
| 		f := func(out, in []byte) { | ||||
| 			Iterated(out, h, in, buf[:8], count) | ||||
| 		} | ||||
| 		return f, nil | ||||
| 	} | ||||
|  | ||||
| 	return nil, errors.UnsupportedError("S2K function") | ||||
| } | ||||
|  | ||||
| // Serialize salts and stretches the given passphrase and writes the | ||||
| // resulting key into key. It also serializes an S2K descriptor to | ||||
| // w. The key stretching can be configured with c, which may be | ||||
| // nil. In that case, sensible defaults will be used. | ||||
| func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { | ||||
| 	var buf [11]byte | ||||
| 	buf[0] = 3 /* iterated and salted */ | ||||
| 	buf[1], _ = HashToHashId(c.hash()) | ||||
| 	salt := buf[2:10] | ||||
| 	if _, err := io.ReadFull(rand, salt); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	encodedCount := c.encodedCount() | ||||
| 	count := decodeCount(encodedCount) | ||||
| 	buf[10] = encodedCount | ||||
| 	if _, err := w.Write(buf[:]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	Iterated(key, c.hash().New(), passphrase, salt, count) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with | ||||
| // Go's crypto.Hash type. See RFC 4880, section 9.4. | ||||
| var hashToHashIdMapping = []struct { | ||||
| 	id   byte | ||||
| 	hash crypto.Hash | ||||
| 	name string | ||||
| }{ | ||||
| 	{1, crypto.MD5, "MD5"}, | ||||
| 	{2, crypto.SHA1, "SHA1"}, | ||||
| 	{3, crypto.RIPEMD160, "RIPEMD160"}, | ||||
| 	{8, crypto.SHA256, "SHA256"}, | ||||
| 	{9, crypto.SHA384, "SHA384"}, | ||||
| 	{10, crypto.SHA512, "SHA512"}, | ||||
| 	{11, crypto.SHA224, "SHA224"}, | ||||
| } | ||||
|  | ||||
| // HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP | ||||
| // hash id. | ||||
| func HashIdToHash(id byte) (h crypto.Hash, ok bool) { | ||||
| 	for _, m := range hashToHashIdMapping { | ||||
| 		if m.id == id { | ||||
| 			return m.hash, true | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
|  | ||||
| // HashIdToString returns the name of the hash function corresponding to the | ||||
| // given OpenPGP hash id, or panics if id is unknown. | ||||
| func HashIdToString(id byte) (name string, ok bool) { | ||||
| 	for _, m := range hashToHashIdMapping { | ||||
| 		if m.id == id { | ||||
| 			return m.name, true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return "", false | ||||
| } | ||||
|  | ||||
| // HashIdToHash returns an OpenPGP hash id which corresponds the given Hash. | ||||
| func HashToHashId(h crypto.Hash) (id byte, ok bool) { | ||||
| 	for _, m := range hashToHashIdMapping { | ||||
| 		if m.hash == h { | ||||
| 			return m.id, true | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
							
								
								
									
										135
									
								
								vendor/github.com/keybase/go-crypto/openpgp/sig-v3.patch
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								vendor/github.com/keybase/go-crypto/openpgp/sig-v3.patch
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| diff --git a/openpgp/read.go b/openpgp/read.go | ||||
| index a6cecc5..0c9397b 100644 | ||||
| --- a/openpgp/read.go | ||||
| +++ b/openpgp/read.go | ||||
| @@ -56,8 +56,9 @@ type MessageDetails struct { | ||||
|  	// been consumed. Once EOF has been seen, the following fields are | ||||
|  	// valid. (An authentication code failure is reported as a | ||||
|  	// SignatureError error when reading from UnverifiedBody.) | ||||
| -	SignatureError error             // nil if the signature is good. | ||||
| -	Signature      *packet.Signature // the signature packet itself. | ||||
| +	SignatureError error               // nil if the signature is good. | ||||
| +	Signature      *packet.Signature   // the signature packet itself, if v4 (default) | ||||
| +	SignatureV3    *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature | ||||
|   | ||||
|  	decrypted io.ReadCloser | ||||
|  } | ||||
| @@ -334,13 +335,15 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { | ||||
|  		} | ||||
|   | ||||
|  		var ok bool | ||||
| -		if scr.md.Signature, ok = p.(*packet.Signature); !ok { | ||||
| +		if scr.md.Signature, ok = p.(*packet.Signature); ok { | ||||
| +			scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | ||||
| +		} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { | ||||
| +			scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) | ||||
| +		} else { | ||||
|  			scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") | ||||
|  			return | ||||
|  		} | ||||
|   | ||||
| -		scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) | ||||
| - | ||||
|  		// The SymmetricallyEncrypted packet, if any, might have an | ||||
|  		// unsigned hash of its own. In order to check this we need to | ||||
|  		// close that Reader. | ||||
| diff --git a/openpgp/read_test.go b/openpgp/read_test.go | ||||
| index 52f942c..abe8d7b 100644 | ||||
| --- a/openpgp/read_test.go | ||||
| +++ b/openpgp/read_test.go | ||||
| @@ -13,6 +13,7 @@ import ( | ||||
|  	"strings" | ||||
|  	"testing" | ||||
|   | ||||
| +	"golang.org/x/crypto/openpgp/armor" | ||||
|  	"golang.org/x/crypto/openpgp/errors" | ||||
|  ) | ||||
|   | ||||
| @@ -411,6 +412,50 @@ func TestIssue11504(t *testing.T) { | ||||
|  	testReadMessageError(t, "9303000130303030303030303030983002303030303030030000000130") | ||||
|  } | ||||
|   | ||||
| +// TestSignatureV3Message tests the verification of V3 signature, generated | ||||
| +// with a modern V4-style key.  Some people have their clients set to generate | ||||
| +// V3 signatures, so it's useful to be able to verify them. | ||||
| +func TestSignatureV3Message(t *testing.T) { | ||||
| +	sig, err := armor.Decode(strings.NewReader(signedMessageV3)) | ||||
| +	if err != nil { | ||||
| +		t.Error(err) | ||||
| +		return | ||||
| +	} | ||||
| +	key, err := ReadArmoredKeyRing(strings.NewReader(keyV4forVerifyingSignedMessageV3)) | ||||
| +	if err != nil { | ||||
| +		t.Error(err) | ||||
| +		return | ||||
| +	} | ||||
| +	md, err := ReadMessage(sig.Body, key, nil, nil) | ||||
| +	if err != nil { | ||||
| +		t.Error(err) | ||||
| +		return | ||||
| +	} | ||||
| + | ||||
| +	_, err = ioutil.ReadAll(md.UnverifiedBody) | ||||
| +	if err != nil { | ||||
| +		t.Error(err) | ||||
| +		return | ||||
| +	} | ||||
| + | ||||
| +	// We'll see a sig error here after reading in the UnverifiedBody above, | ||||
| +	// if there was one to see. | ||||
| +	if err = md.SignatureError; err != nil { | ||||
| +		t.Error(err) | ||||
| +		return | ||||
| +	} | ||||
| + | ||||
| +	if md.SignatureV3 == nil { | ||||
| +		t.Errorf("No available signature after checking signature") | ||||
| +		return | ||||
| +	} | ||||
| +	if md.Signature != nil { | ||||
| +		t.Errorf("Did not expect a signature V4 back") | ||||
| +		return | ||||
| +	} | ||||
| +	return | ||||
| +} | ||||
| + | ||||
|  const testKey1KeyId = 0xA34D7E18C20C31BB | ||||
|  const testKey3KeyId = 0x338934250CCC0360 | ||||
|   | ||||
| @@ -504,3 +549,36 @@ const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6 | ||||
|  const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101` | ||||
|   | ||||
|  const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000` | ||||
| + | ||||
| +const keyV4forVerifyingSignedMessageV3 = `-----BEGIN PGP PUBLIC KEY BLOCK----- | ||||
| +Comment: GPGTools - https://gpgtools.org | ||||
| + | ||||
| +mI0EVfxoFQEEAMBIqmbDfYygcvP6Phr1wr1XI41IF7Qixqybs/foBF8qqblD9gIY | ||||
| +BKpXjnBOtbkcVOJ0nljd3/sQIfH4E0vQwK5/4YRQSI59eKOqd6Fx+fWQOLG+uu6z | ||||
| +tewpeCj9LLHvibx/Sc7VWRnrznia6ftrXxJ/wHMezSab3tnGC0YPVdGNABEBAAG0 | ||||
| +JEdvY3J5cHRvIFRlc3QgS2V5IDx0aGVtYXhAZ21haWwuY29tPoi5BBMBCgAjBQJV | ||||
| +/GgVAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQeXnQmhdGW9PFVAP+ | ||||
| +K7TU0qX5ArvIONIxh/WAweyOk884c5cE8f+3NOPOOCRGyVy0FId5A7MmD5GOQh4H | ||||
| +JseOZVEVCqlmngEvtHZb3U1VYtVGE5WZ+6rQhGsMcWP5qaT4soYwMBlSYxgYwQcx | ||||
| +YhN9qOr292f9j2Y//TTIJmZT4Oa+lMxhWdqTfX+qMgG4jQRV/GgVAQQArhFSiij1 | ||||
| +b+hT3dnapbEU+23Z1yTu1DfF6zsxQ4XQWEV3eR8v+8mEDDNcz8oyyF56k6UQ3rXi | ||||
| +UMTIwRDg4V6SbZmaFbZYCOwp/EmXJ3rfhm7z7yzXj2OFN22luuqbyVhuL7LRdB0M | ||||
| +pxgmjXb4tTvfgKd26x34S+QqUJ7W6uprY4sAEQEAAYifBBgBCgAJBQJV/GgVAhsM | ||||
| +AAoJEHl50JoXRlvT7y8D/02ckx4OMkKBZo7viyrBw0MLG92i+DC2bs35PooHR6zz | ||||
| +786mitjOp5z2QWNLBvxC70S0qVfCIz8jKupO1J6rq6Z8CcbLF3qjm6h1omUBf8Nd | ||||
| +EfXKD2/2HV6zMKVknnKzIEzauh+eCKS2CeJUSSSryap/QLVAjRnckaES/OsEWhNB | ||||
| +=RZia | ||||
| +-----END PGP PUBLIC KEY BLOCK----- | ||||
| +` | ||||
| + | ||||
| +const signedMessageV3 = `-----BEGIN PGP MESSAGE----- | ||||
| +Comment: GPGTools - https://gpgtools.org | ||||
| + | ||||
| +owGbwMvMwMVYWXlhlrhb9GXG03JJDKF/MtxDMjKLFYAoUaEktbhEITe1uDgxPVWP | ||||
| +q5NhKjMrWAVcC9evD8z/bF/uWNjqtk/X3y5/38XGRQHm/57rrDRYuGnTw597Xqka | ||||
| +uM3137/hH3Os+Jf2dc0fXOITKwJvXJvecPVs0ta+Vg7ZO1MLn8w58Xx+6L58mbka | ||||
| +DGHyU9yTueZE8D+QF/Tz28Y78dqtF56R1VPn9Xw4uJqrWYdd7b3vIZ1V6R4Nh05d | ||||
| +iT57d/OhWwA= | ||||
| +=hG7R | ||||
| +-----END PGP MESSAGE----- | ||||
| +` | ||||
							
								
								
									
										495
									
								
								vendor/github.com/keybase/go-crypto/openpgp/write.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										495
									
								
								vendor/github.com/keybase/go-crypto/openpgp/write.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,495 @@ | ||||
| // Copyright 2011 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package openpgp | ||||
|  | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/keybase/go-crypto/openpgp/armor" | ||||
| 	"github.com/keybase/go-crypto/openpgp/errors" | ||||
| 	"github.com/keybase/go-crypto/openpgp/packet" | ||||
| 	"github.com/keybase/go-crypto/openpgp/s2k" | ||||
| ) | ||||
|  | ||||
| // DetachSign signs message with the private key from signer (which must | ||||
| // already have been decrypted) and writes the signature to w. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { | ||||
| 	return detachSign(w, signer, message, packet.SigTypeBinary, config) | ||||
| } | ||||
|  | ||||
| // ArmoredDetachSign signs message with the private key from signer (which | ||||
| // must already have been decrypted) and writes an armored signature to w. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) { | ||||
| 	return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config) | ||||
| } | ||||
|  | ||||
| // DetachSignText signs message (after canonicalising the line endings) with | ||||
| // the private key from signer (which must already have been decrypted) and | ||||
| // writes the signature to w. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { | ||||
| 	return detachSign(w, signer, message, packet.SigTypeText, config) | ||||
| } | ||||
|  | ||||
| // ArmoredDetachSignText signs message (after canonicalising the line endings) | ||||
| // with the private key from signer (which must already have been decrypted) | ||||
| // and writes an armored signature to w. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { | ||||
| 	return armoredDetachSign(w, signer, message, packet.SigTypeText, config) | ||||
| } | ||||
|  | ||||
| func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | ||||
| 	out, err := armor.Encode(w, SignatureType, nil) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = detachSign(out, signer, message, sigType, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return out.Close() | ||||
| } | ||||
|  | ||||
| // SignWithSigner signs the message of type sigType with s and writes the | ||||
| // signature to w. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func SignWithSigner(s packet.Signer, w io.Writer, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | ||||
| 	keyId := s.KeyId() | ||||
| 	sig := new(packet.Signature) | ||||
| 	sig.SigType = sigType | ||||
| 	sig.PubKeyAlgo = s.PublicKeyAlgo() | ||||
| 	sig.Hash = config.Hash() | ||||
| 	sig.CreationTime = config.Now() | ||||
| 	sig.IssuerKeyId = &keyId | ||||
|  | ||||
| 	s.Reset() | ||||
|  | ||||
| 	wrapped := s.(hash.Hash) | ||||
|  | ||||
| 	if sigType == packet.SigTypeText { | ||||
| 		wrapped = NewCanonicalTextHash(s) | ||||
| 	} | ||||
|  | ||||
| 	io.Copy(wrapped, message) | ||||
|  | ||||
| 	err = sig.Sign(s, nil, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err = sig.Serialize(w) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { | ||||
| 	signerSubkey, ok := signer.signingKey(config.Now()) | ||||
| 	if !ok { | ||||
| 		err = errors.InvalidArgumentError("no valid signing keys") | ||||
| 		return | ||||
| 	} | ||||
| 	if signerSubkey.PrivateKey == nil { | ||||
| 		return errors.InvalidArgumentError("signing key doesn't have a private key") | ||||
| 	} | ||||
| 	if signerSubkey.PrivateKey.Encrypted { | ||||
| 		return errors.InvalidArgumentError("signing key is encrypted") | ||||
| 	} | ||||
|  | ||||
| 	sig := new(packet.Signature) | ||||
| 	sig.SigType = sigType | ||||
| 	sig.PubKeyAlgo = signerSubkey.PrivateKey.PubKeyAlgo | ||||
| 	sig.Hash = config.Hash() | ||||
| 	sig.CreationTime = config.Now() | ||||
| 	sig.IssuerKeyId = &signerSubkey.PrivateKey.KeyId | ||||
|  | ||||
| 	h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	io.Copy(wrappedHash, message) | ||||
|  | ||||
| 	err = sig.Sign(h, signerSubkey.PrivateKey, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	return sig.Serialize(w) | ||||
| } | ||||
|  | ||||
| // FileHints contains metadata about encrypted files. This metadata is, itself, | ||||
| // encrypted. | ||||
| type FileHints struct { | ||||
| 	// IsBinary can be set to hint that the contents are binary data. | ||||
| 	IsBinary bool | ||||
| 	// FileName hints at the name of the file that should be written. It's | ||||
| 	// truncated to 255 bytes if longer. It may be empty to suggest that the | ||||
| 	// file should not be written to disk. It may be equal to "_CONSOLE" to | ||||
| 	// suggest the data should not be written to disk. | ||||
| 	FileName string | ||||
| 	// ModTime contains the modification time of the file, or the zero time if not applicable. | ||||
| 	ModTime time.Time | ||||
| } | ||||
|  | ||||
| // SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase. | ||||
| // The resulting WriteCloser must be closed after the contents of the file have | ||||
| // been written. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	if hints == nil { | ||||
| 		hints = &FileHints{} | ||||
| 	} | ||||
|  | ||||
| 	key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	literaldata := w | ||||
| 	if algo := config.Compression(); algo != packet.CompressionNone { | ||||
| 		var compConfig *packet.CompressionConfig | ||||
| 		if config != nil { | ||||
| 			compConfig = config.CompressionConfig | ||||
| 		} | ||||
| 		literaldata, err = packet.SerializeCompressed(w, algo, compConfig) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var epochSeconds uint32 | ||||
| 	if !hints.ModTime.IsZero() { | ||||
| 		epochSeconds = uint32(hints.ModTime.Unix()) | ||||
| 	} | ||||
| 	return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds) | ||||
| } | ||||
|  | ||||
| // intersectPreferences mutates and returns a prefix of a that contains only | ||||
| // the values in the intersection of a and b. The order of a is preserved. | ||||
| func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) { | ||||
| 	var j int | ||||
| 	for _, v := range a { | ||||
| 		for _, v2 := range b { | ||||
| 			if v == v2 { | ||||
| 				a[j] = v | ||||
| 				j++ | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return a[:j] | ||||
| } | ||||
|  | ||||
| func hashToHashId(h crypto.Hash) uint8 { | ||||
| 	v, ok := s2k.HashToHashId(h) | ||||
| 	if !ok { | ||||
| 		panic("tried to convert unknown hash") | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
|  | ||||
| // Encrypt encrypts a message to a number of recipients and, optionally, signs | ||||
| // it. hints contains optional information, that is also encrypted, that aids | ||||
| // the recipients in processing the message. The resulting WriteCloser must | ||||
| // be closed after the contents of the file have been written. | ||||
| // If config is nil, sensible defaults will be used. | ||||
| func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { | ||||
| 	var signer *packet.PrivateKey | ||||
| 	if signed != nil { | ||||
| 		signKey, ok := signed.signingKey(config.Now()) | ||||
| 		if !ok { | ||||
| 			return nil, errors.InvalidArgumentError("no valid signing keys") | ||||
| 		} | ||||
| 		signer = signKey.PrivateKey | ||||
| 		if signer == nil { | ||||
| 			return nil, errors.InvalidArgumentError("no private key in signing key") | ||||
| 		} | ||||
| 		if signer.Encrypted { | ||||
| 			return nil, errors.InvalidArgumentError("signing key must be decrypted") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// These are the possible ciphers that we'll use for the message. | ||||
| 	candidateCiphers := []uint8{ | ||||
| 		uint8(packet.CipherAES128), | ||||
| 		uint8(packet.CipherAES256), | ||||
| 		uint8(packet.CipherCAST5), | ||||
| 	} | ||||
| 	// These are the possible hash functions that we'll use for the signature. | ||||
| 	candidateHashes := []uint8{ | ||||
| 		hashToHashId(crypto.SHA256), | ||||
| 		hashToHashId(crypto.SHA512), | ||||
| 		hashToHashId(crypto.SHA1), | ||||
| 		hashToHashId(crypto.RIPEMD160), | ||||
| 	} | ||||
|  | ||||
| 	// If no preferences were specified, assume something safe and reasonable. | ||||
| 	defaultCiphers := []uint8{ | ||||
| 		uint8(packet.CipherAES128), | ||||
| 		uint8(packet.CipherAES192), | ||||
| 		uint8(packet.CipherAES256), | ||||
| 		uint8(packet.CipherCAST5), | ||||
| 	} | ||||
|  | ||||
| 	defaultHashes := []uint8{ | ||||
| 		hashToHashId(crypto.SHA256), | ||||
| 		hashToHashId(crypto.SHA512), | ||||
| 		hashToHashId(crypto.RIPEMD160), | ||||
| 	} | ||||
|  | ||||
| 	encryptKeys := make([]Key, len(to)) | ||||
| 	for i := range to { | ||||
| 		var ok bool | ||||
| 		encryptKeys[i], ok = to[i].encryptionKey(config.Now()) | ||||
| 		if !ok { | ||||
| 			return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys") | ||||
| 		} | ||||
|  | ||||
| 		sig := to[i].primaryIdentity().SelfSignature | ||||
|  | ||||
| 		preferredSymmetric := sig.PreferredSymmetric | ||||
| 		if len(preferredSymmetric) == 0 { | ||||
| 			preferredSymmetric = defaultCiphers | ||||
| 		} | ||||
| 		preferredHashes := sig.PreferredHash | ||||
| 		if len(preferredHashes) == 0 { | ||||
| 			preferredHashes = defaultHashes | ||||
| 		} | ||||
| 		candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) | ||||
| 		candidateHashes = intersectPreferences(candidateHashes, preferredHashes) | ||||
| 	} | ||||
|  | ||||
| 	if len(candidateCiphers) == 0 { | ||||
| 		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common ciphers") | ||||
| 	} | ||||
| 	if len(candidateHashes) == 0 { | ||||
| 		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common hashes") | ||||
| 	} | ||||
|  | ||||
| 	cipher := packet.CipherFunction(candidateCiphers[0]) | ||||
| 	// If the cipher specifed by config is a candidate, we'll use that. | ||||
| 	configuredCipher := config.Cipher() | ||||
| 	for _, c := range candidateCiphers { | ||||
| 		cipherFunc := packet.CipherFunction(c) | ||||
| 		if cipherFunc == configuredCipher { | ||||
| 			cipher = cipherFunc | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var hash crypto.Hash | ||||
| 	for _, hashId := range candidateHashes { | ||||
| 		if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { | ||||
| 			hash = h | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// If the hash specified by config is a candidate, we'll use that. | ||||
| 	if configuredHash := config.Hash(); configuredHash.Available() { | ||||
| 		for _, hashId := range candidateHashes { | ||||
| 			if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { | ||||
| 				hash = h | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if hash == 0 { | ||||
| 		hashId := candidateHashes[0] | ||||
| 		name, ok := s2k.HashIdToString(hashId) | ||||
| 		if !ok { | ||||
| 			name = "#" + strconv.Itoa(int(hashId)) | ||||
| 		} | ||||
| 		return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") | ||||
| 	} | ||||
|  | ||||
| 	symKey := make([]byte, cipher.KeySize()) | ||||
| 	if _, err := io.ReadFull(config.Random(), symKey); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for _, key := range encryptKeys { | ||||
| 		if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if signer != nil { | ||||
| 		ops := &packet.OnePassSignature{ | ||||
| 			SigType:    packet.SigTypeBinary, | ||||
| 			Hash:       hash, | ||||
| 			PubKeyAlgo: signer.PubKeyAlgo, | ||||
| 			KeyId:      signer.KeyId, | ||||
| 			IsLast:     true, | ||||
| 		} | ||||
| 		if err := ops.Serialize(encryptedData); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if hints == nil { | ||||
| 		hints = &FileHints{} | ||||
| 	} | ||||
|  | ||||
| 	w := encryptedData | ||||
| 	if signer != nil { | ||||
| 		// If we need to write a signature packet after the literal | ||||
| 		// data then we need to stop literalData from closing | ||||
| 		// encryptedData. | ||||
| 		w = noOpCloser{encryptedData} | ||||
|  | ||||
| 	} | ||||
| 	var epochSeconds uint32 | ||||
| 	if !hints.ModTime.IsZero() { | ||||
| 		epochSeconds = uint32(hints.ModTime.Unix()) | ||||
| 	} | ||||
| 	literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if signer != nil { | ||||
| 		return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil | ||||
| 	} | ||||
| 	return literalData, nil | ||||
| } | ||||
|  | ||||
| // signatureWriter hashes the contents of a message while passing it along to | ||||
| // literalData. When closed, it closes literalData, writes a signature packet | ||||
| // to encryptedData and then also closes encryptedData. | ||||
| type signatureWriter struct { | ||||
| 	encryptedData io.WriteCloser | ||||
| 	literalData   io.WriteCloser | ||||
| 	hashType      crypto.Hash | ||||
| 	h             hash.Hash | ||||
| 	signer        *packet.PrivateKey | ||||
| 	config        *packet.Config | ||||
| } | ||||
|  | ||||
| func (s signatureWriter) Write(data []byte) (int, error) { | ||||
| 	s.h.Write(data) | ||||
| 	return s.literalData.Write(data) | ||||
| } | ||||
|  | ||||
| func (s signatureWriter) Close() error { | ||||
| 	sig := &packet.Signature{ | ||||
| 		SigType:      packet.SigTypeBinary, | ||||
| 		PubKeyAlgo:   s.signer.PubKeyAlgo, | ||||
| 		Hash:         s.hashType, | ||||
| 		CreationTime: s.config.Now(), | ||||
| 		IssuerKeyId:  &s.signer.KeyId, | ||||
| 	} | ||||
|  | ||||
| 	if err := sig.Sign(s.h, s.signer, s.config); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := s.literalData.Close(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := sig.Serialize(s.encryptedData); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.encryptedData.Close() | ||||
| } | ||||
|  | ||||
| // noOpCloser is like an ioutil.NopCloser, but for an io.Writer. | ||||
| // TODO: we have two of these in OpenPGP packages alone. This probably needs | ||||
| // to be promoted somewhere more common. | ||||
| type noOpCloser struct { | ||||
| 	w io.Writer | ||||
| } | ||||
|  | ||||
| func (c noOpCloser) Write(data []byte) (n int, err error) { | ||||
| 	return c.w.Write(data) | ||||
| } | ||||
|  | ||||
| func (c noOpCloser) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // AttachedSign is like openpgp.Encrypt (as in p.crypto/openpgp/write.go), but | ||||
| // don't encrypt at all, just sign the literal unencrypted data. | ||||
| // Unfortunately we need to duplicate some code here that's already | ||||
| // in write.go | ||||
| func AttachedSign(out io.WriteCloser, signed Entity, hints *FileHints, | ||||
| 	config *packet.Config) (in io.WriteCloser, err error) { | ||||
|  | ||||
| 	if hints == nil { | ||||
| 		hints = &FileHints{} | ||||
| 	} | ||||
|  | ||||
| 	if config == nil { | ||||
| 		config = &packet.Config{} | ||||
| 	} | ||||
|  | ||||
| 	var signer *packet.PrivateKey | ||||
|  | ||||
| 	signKey, ok := signed.signingKey(config.Now()) | ||||
| 	if !ok { | ||||
| 		err = errors.InvalidArgumentError("no valid signing keys") | ||||
| 		return | ||||
| 	} | ||||
| 	signer = signKey.PrivateKey | ||||
| 	if signer == nil { | ||||
| 		err = errors.InvalidArgumentError("no valid signing keys") | ||||
| 		return | ||||
| 	} | ||||
| 	if signer.Encrypted { | ||||
| 		err = errors.InvalidArgumentError("signing key must be decrypted") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	hasher := crypto.SHA512 | ||||
|  | ||||
| 	ops := &packet.OnePassSignature{ | ||||
| 		SigType:    packet.SigTypeBinary, | ||||
| 		Hash:       hasher, | ||||
| 		PubKeyAlgo: signer.PubKeyAlgo, | ||||
| 		KeyId:      signer.KeyId, | ||||
| 		IsLast:     true, | ||||
| 	} | ||||
|  | ||||
| 	if err = ops.Serialize(out); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var epochSeconds uint32 | ||||
| 	if !hints.ModTime.IsZero() { | ||||
| 		epochSeconds = uint32(hints.ModTime.Unix()) | ||||
| 	} | ||||
|  | ||||
| 	// We don't want the literal serializer to closer the output stream | ||||
| 	// since we're going to need to write to it when we finish up the | ||||
| 	// signature stuff. | ||||
| 	in, err = packet.SerializeLiteral(noOpCloser{out}, hints.IsBinary, hints.FileName, epochSeconds) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// If we need to write a signature packet after the literal | ||||
| 	// data then we need to stop literalData from closing | ||||
| 	// encryptedData. | ||||
| 	in = signatureWriter{out, in, hasher, hasher.New(), signer, config} | ||||
|  | ||||
| 	return | ||||
| } | ||||
		Reference in New Issue
	
	Block a user