// 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. func (e *Entity) SignIdentity(identity string, signer *Entity) os.Error { if signer.PrivateKey == nil { return error.InvalidArgumentError("signing Entity must have a private key") } if signer.PrivateKey.Encrypted { return error.InvalidArgumentError("signing Entity's private key must be decrypted") } ident, ok := e.Identities[identity] if !ok { return error.InvalidArgumentError("given identity string not found in Entity") } sig := &packet.Signature{ SigType: packet.SigTypeGenericCert, PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, Hash: crypto.SHA256, CreationTime: uint32(time.Seconds()), IssuerKeyId: &signer.PrivateKey.KeyId, } if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil { return err } ident.Signatures = append(ident.Signatures, sig) return nil }
// 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 os.Error) { if !pk.CanSign() { return error.InvalidArgumentError("public key cannot generate signatures") } signed.Write(sig.HashSuffix) hashBytes := signed.Sum() if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { return error.SignatureError("hash tag doesn't match") } if pk.PubKeyAlgo != sig.PubKeyAlgo { return error.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) if err != nil { return error.SignatureError("RSA verification failure") } return nil case PubKeyAlgoDSA: dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey) if !dsa.Verify(dsaPublicKey, hashBytes, sig.DSASigR, sig.DSASigS) { return error.SignatureError("DSA verification failure") } return nil default: panic("shouldn't happen") } panic("unreachable") }
func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err error) { if signer.PrivateKey == nil { return error_.InvalidArgumentError("signing key doesn't have a private key") } if signer.PrivateKey.Encrypted { return error_.InvalidArgumentError("signing key is encrypted") } sig := new(packet.Signature) sig.SigType = sigType sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo sig.Hash = crypto.SHA256 sig.CreationTime = uint32(time.Seconds()) sig.IssuerKeyId = &signer.PrivateKey.KeyId h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) if err != nil { return } io.Copy(wrappedHash, message) err = sig.Sign(h, signer.PrivateKey) if err != nil { return } return sig.Serialize(w) }
// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. func ReadArmoredKeyRing(r io.Reader) (EntityList, os.Error) { block, err := armor.Decode(r) if err == os.EOF { return nil, error.InvalidArgumentError("no armored data found") } if err != nil { return nil, err } if block.Type != PublicKeyType && block.Type != PrivateKeyType { return nil, error.InvalidArgumentError("expected public or private key block, got: " + block.Type) } return ReadKeyRing(block.Body) }
// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet // to w and returns a WriteCloser to which the to-be-encrypted packets can be // written. func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte) (contents io.WriteCloser, err os.Error) { if c.KeySize() != len(key) { return nil, error.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 = rand.Reader.Read(iv) if err != nil { return } s, prefix := cipher.NewOCFBEncrypter(block, iv, cipher.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 }
// Decrypt decrypts an encrypted session key with the given private key. The // private key must have been decrypted first. func (e *EncryptedKey) Decrypt(priv *PrivateKey) 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(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1) case PubKeyAlgoElGamal: c1 := new(big.Int).SetBytes(e.encryptedMPI1) c2 := new(big.Int).SetBytes(e.encryptedMPI2) b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) default: err = error_.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 error_.StructuralError("EncryptedKey checksum incorrect") } return nil }
// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. func (sig *Signature) buildHashSuffix() (err os.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 error.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 }
// Serialize marshals sig to w. SignRSA or SignDSA must have been called first. func (sig *Signature) Serialize(w io.Writer) (err os.Error) { if sig.RSASignature == nil && sig.DSASigR == nil { return error.InvalidArgumentError("Signature: need to call SignRSA or SignDSA before Serialize") } sigLength := 0 switch sig.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: sigLength = len(sig.RSASignature) case PubKeyAlgoDSA: sigLength = 2 /* MPI length */ sigLength += (sig.DSASigR.BitLen() + 7) / 8 sigLength += 2 /* MPI length */ sigLength += (sig.DSASigS.BitLen() + 7) / 8 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 */ + 2 /* length of signature MPI */ + 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 = writeMPI(w, 8*uint16(len(sig.RSASignature)), sig.RSASignature) case PubKeyAlgoDSA: err = writeBig(w, sig.DSASigR) if err == nil { err = writeBig(w, sig.DSASigS) } default: panic("impossible") } return }
// Serialize marshals sig to w. SignRSA or SignDSA 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 { return error_.InvalidArgumentError("Signature: need to call SignRSA or SignDSA 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) 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) default: panic("impossible") } return }
// 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". func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, os.Error) { uid := packet.NewUserId(name, comment, email) if uid == nil { return nil, error.InvalidArgumentError("user id field contained invalid characters") } signingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits) if err != nil { return nil, err } encryptingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits) if err != nil { return nil, err } t := uint32(currentTimeSecs) e := &Entity{ PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */), PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */), Identities: make(map[string]*Identity), } isPrimaryId := true e.Identities[uid.Id] = &Identity{ Name: uid.Name, UserId: uid, SelfSignature: &packet.Signature{ CreationTime: t, SigType: packet.SigTypePositiveCert, PubKeyAlgo: packet.PubKeyAlgoRSA, Hash: crypto.SHA256, IsPrimaryId: &isPrimaryId, FlagsValid: true, FlagSign: true, FlagCertify: true, IssuerKeyId: &e.PrimaryKey.KeyId, }, } e.Subkeys = make([]Subkey, 1) e.Subkeys[0] = Subkey{ PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */), PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */), Sig: &packet.Signature{ CreationTime: t, SigType: packet.SigTypeSubkeyBinding, PubKeyAlgo: packet.PubKeyAlgoRSA, Hash: crypto.SHA256, FlagsValid: true, FlagEncryptStorage: true, FlagEncryptCommunications: true, IssuerKeyId: &e.PrimaryKey.KeyId, }, } return e, 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, os.Error) { keySize := c.KeySize() if keySize == 0 { return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) } if len(key) != keySize { return nil, error.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, error.InvalidArgumentError("can't try ciphers with different block lengths") } ocfbResync := cipher.OCFBResync if se.MDC { // MDC packets use a different form of OCFB mode. ocfbResync = cipher.OCFBNoResync } s := cipher.NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) if s == nil { return nil, error.KeyIncorrectError } 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 }
// readArmored reads an armored block with the given type. func readArmored(r io.Reader, expectedType string) (body io.Reader, err os.Error) { block, err := armor.Decode(r) if err != nil { return } if block.Type != expectedType { return nil, error.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type) } return block.Body, nil }
func (pk *PrivateKey) Serialize(w io.Writer) (err os.Error) { // TODO(agl): support encrypted private keys buf := bytes.NewBuffer(nil) err = pk.PublicKey.serializeWithoutHeaders(buf) if err != nil { return } buf.WriteByte(0 /* no encryption */) privateKeyBuf := bytes.NewBuffer(nil) switch priv := pk.PrivateKey.(type) { case *rsa.PrivateKey: err = serializeRSAPrivateKey(privateKeyBuf, priv) default: err = error.InvalidArgumentError("non-RSA private key") } if err != nil { return } ptype := packetTypePrivateKey contents := buf.Bytes() privateKeyBytes := privateKeyBuf.Bytes() if pk.IsSubkey { ptype = packetTypePrivateSubkey } err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2) if err != nil { return } _, err = w.Write(contents) if err != nil { return } _, err = w.Write(privateKeyBytes) if err != nil { return } checksum := mod64kHash(privateKeyBytes) var checksumBytes [2]byte checksumBytes[0] = byte(checksum >> 8) checksumBytes[1] = byte(checksum) _, err = w.Write(checksumBytes[:]) return }
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 error_.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) }
// DecryptRSA decrypts an RSA encrypted session key with the given private key. func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) { if e.Algo != PubKeyAlgoRSA && e.Algo != PubKeyAlgoRSAEncryptOnly { return error.InvalidArgumentError("EncryptedKey not RSA encrypted") } b, err := rsa.DecryptPKCS1v15(rand.Reader, priv, e.Encrypted) if err != nil { return } e.CipherFunc = CipherFunction(b[0]) e.Key = b[1 : len(b)-2] expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) var checksum uint16 for _, v := range e.Key { checksum += uint16(v) } if checksum != expectedChecksum { return error.StructuralError("EncryptedKey checksum incorrect") } return }
// 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 os.Error) { var buf [6]byte buf[0] = 4 buf[1] = byte(pk.CreationTime >> 24) buf[2] = byte(pk.CreationTime >> 16) buf[3] = byte(pk.CreationTime >> 8) buf[4] = byte(pk.CreationTime) 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) } return error.InvalidArgumentError("bad public-key algorithm") }
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 error_.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) }
// SerializeEncryptedKey serializes an encrypted key packet to w that contains // key, encrypted to pub. func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) 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, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) case PubKeyAlgoElGamal: return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: return error_.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) } return error_.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) }
// 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. func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err error) { var signer *packet.PrivateKey if signed != nil { signer = signed.signingKey().PrivateKey if signer == nil || signer.Encrypted { return nil, error_.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), } // In the event that a recipient doesn't specify any supported ciphers // or hash functions, these are the ones that we assume that every // implementation supports. defaultCiphers := candidateCiphers[len(candidateCiphers)-1:] defaultHashes := candidateHashes[len(candidateHashes)-1:] encryptKeys := make([]Key, len(to)) for i := range to { encryptKeys[i] = to[i].encryptionKey() if encryptKeys[i].PublicKey == nil { return nil, error_.InvalidArgumentError("cannot encrypt a message to key id " + strconv.Uitob64(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 || len(candidateHashes) == 0 { return nil, error_.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") } cipher := packet.CipherFunction(candidateCiphers[0]) hash, _ := s2k.HashIdToHash(candidateHashes[0]) symKey := make([]byte, cipher.KeySize()) if _, err := io.ReadFull(rand.Reader, symKey); err != nil { return nil, err } for _, key := range encryptKeys { if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil { return nil, err } } encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey) 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} } literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) if err != nil { return nil, err } if signer != nil { return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil } return literalData, nil }