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 (
	
	
	
	
	
	
	
	
	
	

	
)
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.
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 ( time.Time,  *rsa.PublicKey) *PublicKeyV3 {
	 := &PublicKeyV3{
		CreationTime: ,
		PublicKey:    ,
		n:            fromBig(.N),
		e:            fromBig(big.NewInt(int64(.E))),
	}

	.setFingerPrintAndKeyId()
	return 
}

RFC 4880, section 5.5.2
	var  [8]byte
	if _,  = readFull(, [:]);  != nil {
		return
	}
	if [0] < 2 || [0] > 3 {
		return errors.UnsupportedError("public key version")
	}
	.CreationTime = time.Unix(int64(uint32([1])<<24|uint32([2])<<16|uint32([3])<<8|uint32([4])), 0)
	.DaysToExpire = binary.BigEndian.Uint16([5:7])
	.PubKeyAlgo = PublicKeyAlgorithm([7])
	switch .PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
		 = .parseRSA()
	default:
		 = errors.UnsupportedError("public key type: " + strconv.Itoa(int(.PubKeyAlgo)))
	}
	if  != nil {
		return
	}

	.setFingerPrintAndKeyId()
	return
}

RFC 4880, section 12.2
	 := md5.New()
	.Write(.n.bytes)
	.Write(.e.bytes)
	.Sum(.Fingerprint[:0])
	.KeyId = binary.BigEndian.Uint64(.n.bytes[len(.n.bytes)-8:])
}
parseRSA parses RSA public key material from the given Reader. See RFC 4880, section 5.5.2.
func ( *PublicKeyV3) ( io.Reader) ( error) {
	if .n.bytes, .n.bitLength,  = readMPI();  != nil {
		return
	}
	if .e.bytes, .e.bitLength,  = readMPI();  != nil {
		return
	}
RFC 4880 Section 12.2 requires the low 8 bytes of the modulus to form the key id.
	if len(.n.bytes) < 8 {
		return errors.StructuralError("v3 public key modulus is too short")
	}
	if len(.e.bytes) > 3 {
		 = errors.UnsupportedError("large public exponent")
		return
	}
	 := &rsa.PublicKey{N: new(big.Int).SetBytes(.n.bytes)}
	for  := 0;  < len(.e.bytes); ++ {
		.E <<= 8
		.E |= int(.e.bytes[])
	}
	.PublicKey = 
	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 ( *PublicKeyV3) ( io.Writer) {
	var  uint16
	switch .PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
		 += 2 + uint16(len(.n.bytes))
		 += 2 + uint16(len(.e.bytes))
	default:
		panic("unknown public key algorithm")
	}
	 += 6
	.Write([]byte{0x99, byte( >> 8), byte()})
	return
}

func ( *PublicKeyV3) ( io.Writer) ( error) {
	 := 8 // 8 byte header

	switch .PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
		 += 2 + len(.n.bytes)
		 += 2 + len(.e.bytes)
	default:
		panic("unknown public key algorithm")
	}

	 := packetTypePublicKey
	if .IsSubkey {
		 = packetTypePublicSubkey
	}
	if  = serializeHeader(, , );  != nil {
		return
	}
	return .serializeWithoutHeaders()
}
serializeWithoutHeaders marshals the PublicKey to w in the form of an OpenPGP public key packet, not including the packet header.
Version 3
Creation time
	 := uint32(.CreationTime.Unix())
	[1] = byte( >> 24)
	[2] = byte( >> 16)
	[3] = byte( >> 8)
Days to expire
	[5] = byte(.DaysToExpire >> 8)
Public key algorithm
	[7] = byte(.PubKeyAlgo)

	if _,  = .Write([:]);  != nil {
		return
	}

	switch .PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
		return writeMPIs(, .n, .e)
	}
	return errors.InvalidArgumentError("bad public-key algorithm")
}
CanSign returns true iff this public key can generate signatures
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 ( *PublicKeyV3) ( hash.Hash,  *SignatureV3) ( error) {
	if !.CanSign() {
		return errors.InvalidArgumentError("public key cannot generate signatures")
	}

	 := make([]byte, 5)
	[0] = byte(.SigType)
	binary.BigEndian.PutUint32([1:], uint32(.CreationTime.Unix()))
	.Write()
	 := .Sum(nil)

	if [0] != .HashTag[0] || [1] != .HashTag[1] {
		return errors.SignatureError("hash tag doesn't match")
	}

	if .PubKeyAlgo != .PubKeyAlgo {
		return errors.InvalidArgumentError("public key and signature use different algorithms")
	}

	switch .PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
		if  = rsa.VerifyPKCS1v15(.PublicKey, .Hash, , .RSASignature.bytes);  != nil {
			return errors.SignatureError("RSA verification failure")
		}
		return
V3 public keys only support RSA.
		panic("shouldn't happen")
	}
}
VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this public key, that id is the identity of pub.
func ( *PublicKeyV3) ( string,  *PublicKeyV3,  *SignatureV3) ( error) {
	,  := userIdSignatureV3Hash(, , .Hash)
	if  != nil {
		return 
	}
	return .VerifySignatureV3(, )
}
VerifyKeySignatureV3 returns nil iff sig is a valid signature, made by this public key, of signed.
func ( *PublicKeyV3) ( *PublicKeyV3,  *SignatureV3) ( error) {
	,  := keySignatureHash(, , .Hash)
	if  != nil {
		return 
	}
	return .VerifySignatureV3(, )
}
userIdSignatureV3Hash returns a Hash of the message that needs to be signed to assert that pk is a valid key for id.
func ( string,  signingKey,  crypto.Hash) ( hash.Hash,  error) {
	if !.Available() {
		return nil, errors.UnsupportedError("hash function")
	}
	 = .New()
RFC 4880, section 5.2.4
KeyIdString returns the public key's fingerprint in capital hex (e.g. "6C7EE1B8621CC013").
func ( *PublicKeyV3) () string {
	return fmt.Sprintf("%X", .KeyId)
}
KeyIdShortString returns the short form of public key's fingerprint in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
func ( *PublicKeyV3) () string {
	return fmt.Sprintf("%X", .KeyId&0xFFFFFFFF)
}
BitLength returns the bit length for the given public key.
func ( *PublicKeyV3) () ( uint16,  error) {
	switch .PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
		 = .n.bitLength
	default:
		 = errors.InvalidArgumentError("bad public-key algorithm")
	}
	return