Switch to keybase go-crypto (for some elliptic curve key) + test (#1925)
* Switch to keybase go-crypto (for some elliptic curve key) + test
* Use assert.NoError
and add a little more context to failing test description
* Use assert.(No)Error everywhere 🌈
and assert.Error in place of .Nil/.NotNil
This commit is contained in:
parent
5e92b82ac6
commit
274149dd14
56 changed files with 10621 additions and 925 deletions
550
vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go
generated
vendored
Normal file
550
vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go
generated
vendored
Normal file
|
@ -0,0 +1,550 @@
|
|||
// 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"
|
||||
"crypto/cipher"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/keybase/go-crypto/ed25519"
|
||||
"github.com/keybase/go-crypto/openpgp/ecdh"
|
||||
"github.com/keybase/go-crypto/openpgp/elgamal"
|
||||
"github.com/keybase/go-crypto/openpgp/errors"
|
||||
"github.com/keybase/go-crypto/openpgp/s2k"
|
||||
"github.com/keybase/go-crypto/rsa"
|
||||
)
|
||||
|
||||
// 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 or *dsa.PrivateKey.
|
||||
sha1Checksum bool
|
||||
iv []byte
|
||||
s2kHeader []byte
|
||||
}
|
||||
|
||||
type EdDSAPrivateKey struct {
|
||||
PrivateKey
|
||||
seed parsedMPI
|
||||
}
|
||||
|
||||
func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) {
|
||||
r := bytes.NewReader(e.seed.bytes)
|
||||
publicKey, privateKey, err := ed25519.GenerateKey(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !bytes.Equal(publicKey, e.PublicKey.edk.p.bytes[1:]) { // [1:] because [0] is 0x40 mpi header
|
||||
return nil, nil, errors.UnsupportedError("EdDSA: Private key does not match public key.")
|
||||
}
|
||||
|
||||
sig := ed25519.Sign(privateKey, digest)
|
||||
|
||||
sigLen := ed25519.SignatureSize / 2
|
||||
return sig[:sigLen], sig[sigLen:], nil
|
||||
}
|
||||
|
||||
func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
|
||||
pk := new(PrivateKey)
|
||||
pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey)
|
||||
pk.PrivateKey = priv
|
||||
return pk
|
||||
}
|
||||
|
||||
func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
|
||||
pk := new(PrivateKey)
|
||||
pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey)
|
||||
pk.PrivateKey = priv
|
||||
return pk
|
||||
}
|
||||
|
||||
func NewElGamalPrivateKey(currentTime time.Time, priv *elgamal.PrivateKey) *PrivateKey {
|
||||
pk := new(PrivateKey)
|
||||
pk.PublicKey = *NewElGamalPublicKey(currentTime, &priv.PublicKey)
|
||||
pk.PrivateKey = priv
|
||||
return pk
|
||||
}
|
||||
|
||||
func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey {
|
||||
pk := new(PrivateKey)
|
||||
pk.PublicKey = *NewECDSAPublicKey(currentTime, &priv.PublicKey)
|
||||
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
|
||||
}
|
||||
// S2K == nil implies that we got a "GNU Dummy" S2K. For instance,
|
||||
// because our master secret key is on a USB key in a vault somewhere.
|
||||
// In that case, there is no further data to consume here.
|
||||
if pk.s2k == nil {
|
||||
pk.Encrypted = false
|
||||
return
|
||||
}
|
||||
default:
|
||||
return errors.UnsupportedError("deprecated s2k function in private key")
|
||||
}
|
||||
if pk.Encrypted {
|
||||
blockSize := pk.cipher.blockSize()
|
||||
if blockSize == 0 {
|
||||
return errors.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 {
|
||||
var h uint16
|
||||
for _, b := range d {
|
||||
h += uint16(b)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Encrypt is the counterpart to the Decrypt() method below. It encrypts
|
||||
// the private key with the provided passphrase. If config is nil, then
|
||||
// the standard, and sensible, defaults apply.
|
||||
//
|
||||
// A key will be derived from the given passphrase using S2K Specifier
|
||||
// Type 3 (Iterated + Salted, see RFC-4880 Sec. 3.7.1.3). This choice
|
||||
// is hardcoded in s2k.Serialize(). S2KCount is hardcoded to 0, which is
|
||||
// equivalent to 65536. And the hash algorithm for key-derivation can be
|
||||
// set with config. The encrypted PrivateKey, using the algorithm specified
|
||||
// in config (if provided), is written out to the encryptedData member.
|
||||
// When Serialize() is called, this encryptedData member will be
|
||||
// serialized, using S2K Usage value of 254, and thus SHA1 checksum.
|
||||
func (pk *PrivateKey) Encrypt(passphrase []byte, config *Config) (err error) {
|
||||
if pk.PrivateKey == nil {
|
||||
return errors.InvalidArgumentError("there is no private key to encrypt")
|
||||
}
|
||||
|
||||
pk.sha1Checksum = true
|
||||
pk.cipher = config.Cipher()
|
||||
s2kConfig := s2k.Config{
|
||||
Hash: config.Hash(),
|
||||
S2KCount: 0,
|
||||
}
|
||||
s2kBuf := bytes.NewBuffer(nil)
|
||||
derivedKey := make([]byte, pk.cipher.KeySize())
|
||||
err = s2k.Serialize(s2kBuf, derivedKey, config.Random(), passphrase, &s2kConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pk.s2kHeader = s2kBuf.Bytes()
|
||||
// No good way to set pk.s2k but to call s2k.Parse(),
|
||||
// even though we have all the information here, but
|
||||
// most of the functions needed are private to s2k.
|
||||
pk.s2k, err = s2k.Parse(s2kBuf)
|
||||
pk.iv = make([]byte, pk.cipher.blockSize())
|
||||
if _, err = config.Random().Read(pk.iv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privateKeyBuf := bytes.NewBuffer(nil)
|
||||
if err = pk.serializePrivateKey(privateKeyBuf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
checksum := sha1.Sum(privateKeyBuf.Bytes())
|
||||
if _, err = privateKeyBuf.Write(checksum[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkData := privateKeyBuf.Bytes()
|
||||
block := pk.cipher.new(derivedKey)
|
||||
pk.encryptedData = make([]byte, len(pkData))
|
||||
cfb := cipher.NewCFBEncrypter(block, pk.iv)
|
||||
cfb.XORKeyStream(pk.encryptedData, pkData)
|
||||
pk.Encrypted = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err = pk.PublicKey.serializeWithoutHeaders(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
privateKeyBuf := bytes.NewBuffer(nil)
|
||||
|
||||
if pk.PrivateKey == nil {
|
||||
_, err = buf.Write([]byte{
|
||||
254, // SHA-1 Convention
|
||||
9, // Encryption scheme (AES256)
|
||||
101, // GNU Extensions
|
||||
2, // Hash value (SHA1)
|
||||
'G', 'N', 'U', // "GNU" as a string
|
||||
1, // Extension type 1001 (minus 1000)
|
||||
})
|
||||
} else if pk.Encrypted {
|
||||
_, err = buf.Write([]byte{
|
||||
254, // SHA-1 Convention
|
||||
byte(pk.cipher), // Encryption scheme
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = buf.Write(pk.s2kHeader); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = buf.Write(pk.iv); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = privateKeyBuf.Write(pk.encryptedData); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
buf.WriteByte(0 /* no encryption */)
|
||||
if err = pk.serializePrivateKey(privateKeyBuf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ptype := packetTypePrivateKey
|
||||
contents := buf.Bytes()
|
||||
privateKeyBytes := privateKeyBuf.Bytes()
|
||||
if pk.IsSubkey {
|
||||
ptype = packetTypePrivateSubkey
|
||||
}
|
||||
totalLen := len(contents) + len(privateKeyBytes)
|
||||
if !pk.Encrypted {
|
||||
totalLen += 2
|
||||
}
|
||||
err = serializeHeader(w, ptype, totalLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(contents)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(privateKeyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(privateKeyBytes) > 0 && !pk.Encrypted {
|
||||
checksum := mod64kHash(privateKeyBytes)
|
||||
var checksumBytes [2]byte
|
||||
checksumBytes[0] = byte(checksum >> 8)
|
||||
checksumBytes[1] = byte(checksum)
|
||||
_, err = w.Write(checksumBytes[:])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) {
|
||||
switch priv := pk.PrivateKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
err = serializeRSAPrivateKey(w, priv)
|
||||
case *dsa.PrivateKey:
|
||||
err = serializeDSAPrivateKey(w, priv)
|
||||
case *elgamal.PrivateKey:
|
||||
err = serializeElGamalPrivateKey(w, priv)
|
||||
case *ecdsa.PrivateKey:
|
||||
err = serializeECDSAPrivateKey(w, priv)
|
||||
case *ecdh.PrivateKey:
|
||||
err = serializeECDHPrivateKey(w, priv)
|
||||
case *EdDSAPrivateKey:
|
||||
err = serializeEdDSAPrivateKey(w, priv)
|
||||
default:
|
||||
err = errors.InvalidArgumentError("unknown private key type")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error {
|
||||
return writeBig(w, priv.X)
|
||||
}
|
||||
|
||||
func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error {
|
||||
return writeBig(w, priv.X)
|
||||
}
|
||||
|
||||
func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error {
|
||||
return writeBig(w, priv.D)
|
||||
}
|
||||
|
||||
func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error {
|
||||
return writeBig(w, priv.X)
|
||||
}
|
||||
|
||||
func serializeEdDSAPrivateKey(w io.Writer, priv *EdDSAPrivateKey) error {
|
||||
return writeMPI(w, priv.seed.bitLength, priv.seed.bytes)
|
||||
}
|
||||
|
||||
// Decrypt decrypts an encrypted private key using a passphrase.
|
||||
func (pk *PrivateKey) Decrypt(passphrase []byte) error {
|
||||
if !pk.Encrypted {
|
||||
return nil
|
||||
}
|
||||
// For GNU Dummy S2K, there's no key here, so don't do anything.
|
||||
if pk.s2k == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
key := make([]byte, pk.cipher.KeySize())
|
||||
pk.s2k(key, passphrase)
|
||||
block := pk.cipher.new(key)
|
||||
cfb := cipher.NewCFBDecrypter(block, pk.iv)
|
||||
|
||||
data := make([]byte, len(pk.encryptedData))
|
||||
cfb.XORKeyStream(data, pk.encryptedData)
|
||||
|
||||
if pk.sha1Checksum {
|
||||
if len(data) < sha1.Size {
|
||||
return errors.StructuralError("truncated private key data")
|
||||
}
|
||||
h := sha1.New()
|
||||
h.Write(data[:len(data)-sha1.Size])
|
||||
sum := h.Sum(nil)
|
||||
if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
|
||||
return errors.StructuralError("private key checksum failure")
|
||||
}
|
||||
data = data[:len(data)-sha1.Size]
|
||||
} else {
|
||||
if len(data) < 2 {
|
||||
return errors.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 errors.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)
|
||||
case PubKeyAlgoECDSA:
|
||||
return pk.parseECDSAPrivateKey(data)
|
||||
case PubKeyAlgoECDH:
|
||||
return pk.parseECDHPrivateKey(data)
|
||||
case PubKeyAlgoEdDSA:
|
||||
return pk.parseEdDSAPrivateKey(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)
|
||||
if err := rsaPriv.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) {
|
||||
pub := pk.PublicKey.PublicKey.(*ecdh.PublicKey)
|
||||
priv := new(ecdh.PrivateKey)
|
||||
priv.PublicKey = *pub
|
||||
|
||||
buf := bytes.NewBuffer(data)
|
||||
d, _, err := readMPI(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
priv.X = new(big.Int).SetBytes(d)
|
||||
pk.PrivateKey = priv
|
||||
pk.Encrypted = false
|
||||
pk.encryptedData = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) {
|
||||
ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey)
|
||||
ecdsaPriv := new(ecdsa.PrivateKey)
|
||||
ecdsaPriv.PublicKey = *ecdsaPub
|
||||
|
||||
buf := bytes.NewBuffer(data)
|
||||
d, _, err := readMPI(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ecdsaPriv.D = new(big.Int).SetBytes(d)
|
||||
pk.PrivateKey = ecdsaPriv
|
||||
pk.Encrypted = false
|
||||
pk.encryptedData = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) {
|
||||
eddsaPriv := new(EdDSAPrivateKey)
|
||||
eddsaPriv.PublicKey = pk.PublicKey
|
||||
|
||||
buf := bytes.NewBuffer(data)
|
||||
eddsaPriv.seed.bytes, eddsaPriv.seed.bitLength, err = readMPI(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bLen := len(eddsaPriv.seed.bytes); bLen != 32 { // 32 bytes private part of ed25519 key.
|
||||
return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA private key length: %d", bLen))
|
||||
}
|
||||
|
||||
pk.PrivateKey = eddsaPriv
|
||||
pk.Encrypted = false
|
||||
pk.encryptedData = nil
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue