blob: 19eb4780639178bcf1b396b5461ecf91216d1b52 [file] [log] [blame]
// Copyright 2016 The Upspin 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 ee // import "upspin.io/pack/ee"
import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/binary"
"upspin.io/errors"
"upspin.io/upspin"
)
// drng is an io.Reader returning deterministic random bits seeded from aesKey.
type drng struct {
aes cipher.Block
counter uint32
random []byte
}
func (d *drng) Read(p []byte) (n int, err error) {
lenp := len(p)
n = lenp
var drand [16]byte
for n > 0 {
if len(d.random) == 0 {
binary.BigEndian.PutUint32(drand[0:4], d.counter)
d.counter++
binary.BigEndian.PutUint32(drand[4:8], d.counter)
d.counter++
binary.BigEndian.PutUint32(drand[8:12], d.counter)
d.counter++
binary.BigEndian.PutUint32(drand[12:16], d.counter)
d.counter++
d.random = drand[:]
d.aes.Encrypt(d.random, d.random)
}
m := copy(p, d.random)
n -= m
p = p[m:]
d.random = d.random[m:]
}
return lenp, nil
}
// CreateKeys creates a key pair based on the chosen curve and a slice of entropy.
func CreateKeys(curveName string, entropy []byte) (public upspin.PublicKey, private string, err error) {
const op errors.Op = "pack/ee.CreateKeys"
var curve elliptic.Curve
switch curveName {
case "p256":
curve = elliptic.P256()
case "p384":
curve = elliptic.P384()
case "p521":
curve = elliptic.P521()
default:
return public, private, errors.E(op, errors.Invalid, errors.Errorf("curveName %s", curveName))
}
priv, err := createKeysFromEntropy(curve, entropy)
if err != nil {
return public, private, errors.E(op, errors.Invalid, err)
}
public, private = encodeKeys(priv, curveName)
return
}
// GenEntropy fills the slice with cryptographically-secure random bytes.
func GenEntropy(entropy []byte) error {
_, err := rand.Read(entropy)
return err
}
// encodeKeys converts an ecsda private key into an upspin key pair. No error checking is performed.
func encodeKeys(priv *ecdsa.PrivateKey, curveName string) (public upspin.PublicKey, private string) {
private = priv.D.String() + "\n"
public = upspin.PublicKey(curveName + "\n" + priv.X.String() + "\n" + priv.Y.String() + "\n")
return
}
// createKeysFromEntropy creates an ecsda private key from a given entropy.
func createKeysFromEntropy(curve elliptic.Curve, entropy []byte) (*ecdsa.PrivateKey, error) {
// Create crypto deterministic random generator from b.
d := &drng{}
cipher, err := aes.NewCipher(entropy)
if err != nil {
return nil, err
}
d.aes = cipher
// Generate random key-pair.
priv, err := ecdsa.GenerateKey(curve, d)
if err != nil {
return nil, err
}
return priv, nil
}