| // 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 ( |
| "big" |
| "bytes" |
| "crypto/cipher" |
| "crypto/dsa" |
| "crypto/openpgp/elgamal" |
| error_ "crypto/openpgp/error" |
| "crypto/openpgp/s2k" |
| "crypto/rsa" |
| "crypto/sha1" |
| "io" |
| "io/ioutil" |
| "strconv" |
| ) |
| |
| // 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. |
| sha1Checksum bool |
| iv []byte |
| } |
| |
| func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey { |
| pk := new(PrivateKey) |
| pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey) |
| 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 |
| } |
| default: |
| return error_.UnsupportedError("deprecated s2k function in private key") |
| } |
| |
| if pk.Encrypted { |
| blockSize := pk.cipher.blockSize() |
| if blockSize == 0 { |
| return error_.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 { |
| h := uint16(0) |
| for i := 0; i < len(d); i += 2 { |
| v := uint16(d[i]) << 8 |
| if i+1 < len(d) { |
| v += uint16(d[i+1]) |
| } |
| h += v |
| } |
| return h |
| } |
| |
| func (pk *PrivateKey) Serialize(w io.Writer) (err 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 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) |
| } |
| |
| // Decrypt decrypts an encrypted private key using a passphrase. |
| func (pk *PrivateKey) Decrypt(passphrase []byte) error { |
| if !pk.Encrypted { |
| return nil |
| } |
| |
| key := make([]byte, pk.cipher.KeySize()) |
| pk.s2k(key, passphrase) |
| block := pk.cipher.new(key) |
| cfb := cipher.NewCFBDecrypter(block, pk.iv) |
| |
| data := pk.encryptedData |
| cfb.XORKeyStream(data, data) |
| |
| if pk.sha1Checksum { |
| if len(data) < sha1.Size { |
| return error_.StructuralError("truncated private key data") |
| } |
| h := sha1.New() |
| h.Write(data[:len(data)-sha1.Size]) |
| sum := h.Sum() |
| if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { |
| return error_.StructuralError("private key checksum failure") |
| } |
| data = data[:len(data)-sha1.Size] |
| } else { |
| if len(data) < 2 { |
| return error_.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 error_.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) |
| } |
| 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) |
| 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 |
| } |