mirror of
https://github.com/Luzifer/cloudkeys-go.git
synced 2024-11-10 07:00:08 +00:00
Knut Ahlers
a1df72edc5
commitf0db1ff1f8
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:19:56 2017 +0100 Mark option as deprecated Signed-off-by: Knut Ahlers <knut@ahlers.me> commit9891df2a16
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:11:56 2017 +0100 Fix: Typo Signed-off-by: Knut Ahlers <knut@ahlers.me> commit836006de64
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:04:20 2017 +0100 Add new dependencies Signed-off-by: Knut Ahlers <knut@ahlers.me> commitd64fee60c8
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 11:55:52 2017 +0100 Replace insecure password hashing Prior this commit passwords were hashed with a static salt and using the SHA1 hashing function. This could lead to passwords being attackable in case someone gets access to the raw data stored inside the database. This commit introduces password hashing using bcrypt hashing function which addresses this issue. Old passwords are not automatically re-hashed as they are unknown. Replacing the old password scheme is not that easy and needs #10 to be solved. Therefore the old hashing scheme is kept for compatibility reason. Signed-off-by: Knut Ahlers <knut@ahlers.me> Signed-off-by: Knut Ahlers <knut@ahlers.me> closes #14 closes #15
537 lines
13 KiB
Go
537 lines
13 KiB
Go
// 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 "golang.org/x/crypto/openpgp/packet"
|
|
|
|
import (
|
|
"bufio"
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/des"
|
|
"golang.org/x/crypto/cast5"
|
|
"golang.org/x/crypto/openpgp/errors"
|
|
"io"
|
|
"math/big"
|
|
)
|
|
|
|
// 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
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
)
|
|
|
|
// 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
|
|
)
|
|
|
|
// 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:
|
|
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:
|
|
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
|
|
}
|
|
|
|
// 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
|
|
)
|