mirror of
https://github.com/golang/go
synced 2024-11-12 09:20:22 -07:00
crypto/openpgp/packet: two more packet types.
R=bradfitzgo, r CC=golang-dev https://golang.org/cl/4124054
This commit is contained in:
parent
d812e8c994
commit
c63a88072b
39
src/pkg/crypto/openpgp/packet/compressed.go
Normal file
39
src/pkg/crypto/openpgp/packet/compressed.go
Normal file
@ -0,0 +1,39 @@
|
||||
// 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/flate"
|
||||
"compress/zlib"
|
||||
"crypto/openpgp/error"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (c *Compressed) parse(r io.Reader) os.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)
|
||||
default:
|
||||
err = error.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
41
src/pkg/crypto/openpgp/packet/compressed_test.go
Normal file
41
src/pkg/crypto/openpgp/packet/compressed_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
// 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"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompressed(t *testing.T) {
|
||||
packet, err := Read(readerFromHex(compressedHex))
|
||||
if err != nil {
|
||||
t.Errorf("failed to read Compressed: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
c, ok := packet.(*Compressed)
|
||||
if !ok {
|
||||
t.Error("didn't find Compressed packet")
|
||||
return
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadAll(c.Body)
|
||||
if err != nil && err != os.EOF {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
expected, _ := hex.DecodeString(compressedExpectedHex)
|
||||
if !bytes.Equal(expected, contents) {
|
||||
t.Errorf("got:%x want:%x", contents, expected)
|
||||
}
|
||||
}
|
||||
|
||||
const compressedHex = "a3013b2d90c4e02b72e25f727e5e496a5e49b11e1700"
|
||||
const compressedExpectedHex = "cb1062004d14c8fe636f6e74656e74732e0a"
|
164
src/pkg/crypto/openpgp/packet/private_key.go
Normal file
164
src/pkg/crypto/openpgp/packet/private_key.go
Normal file
@ -0,0 +1,164 @@
|
||||
// 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/openpgp/error"
|
||||
"crypto/openpgp/s2k"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"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 (pk *PrivateKey) parse(r io.Reader) (err os.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
|
||||
}
|
||||
|
||||
// Decrypt decrypts an encrypted private key using a passphrase.
|
||||
func (pk *PrivateKey) Decrypt(passphrase []byte) os.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 os.Error) {
|
||||
// TODO(agl): support DSA and ECDSA private keys.
|
||||
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.P = new(big.Int).SetBytes(p)
|
||||
rsaPriv.Q = new(big.Int).SetBytes(q)
|
||||
pk.PrivateKey = rsaPriv
|
||||
pk.Encrypted = false
|
||||
pk.encryptedData = nil
|
||||
|
||||
return nil
|
||||
}
|
37
src/pkg/crypto/openpgp/packet/private_key_test.go
Normal file
37
src/pkg/crypto/openpgp/packet/private_key_test.go
Normal file
@ -0,0 +1,37 @@
|
||||
// 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 (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPrivateKeyRead(t *testing.T) {
|
||||
packet, err := Read(readerFromHex(privKeyHex))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
privKey := packet.(*PrivateKey)
|
||||
|
||||
if !privKey.Encrypted {
|
||||
t.Error("private key isn't encrypted")
|
||||
return
|
||||
}
|
||||
|
||||
err = privKey.Decrypt([]byte("testing"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if privKey.CreationTime != 0x4cc349a8 || privKey.Encrypted {
|
||||
t.Errorf("failed to parse, got: %#v", privKey)
|
||||
}
|
||||
}
|
||||
|
||||
// Generated with `gpg --export-secret-keys "Test Key 2"`
|
||||
const privKeyHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
|
Loading…
Reference in New Issue
Block a user