From 11b42f83abc8aa8f676df2f2ec49fada8acaea5b Mon Sep 17 00:00:00 2001 From: nsz Date: Tue, 29 Nov 2011 17:20:11 +0100 Subject: [PATCH] add simple dsa key generator --- cmd/genkey/Makefile | 7 +++ cmd/genkey/genkey.go | 81 ++++++++++++++++++++++++++++++++ dsakey/Makefile | 6 +++ dsakey/dsakey.go | 106 ++++++++++++++++++++++++++++++++++++++++++ dsakey/dsakey_test.go | 38 +++++++++++++++ 5 files changed, 238 insertions(+) create mode 100644 cmd/genkey/Makefile create mode 100644 cmd/genkey/genkey.go create mode 100644 dsakey/Makefile create mode 100644 dsakey/dsakey.go create mode 100644 dsakey/dsakey_test.go diff --git a/cmd/genkey/Makefile b/cmd/genkey/Makefile new file mode 100644 index 0000000..4af0d05 --- /dev/null +++ b/cmd/genkey/Makefile @@ -0,0 +1,7 @@ +include $(GOROOT)/src/Make.inc + +TARG=genkey +GOFILES=\ + genkey.go + +include $(GOROOT)/src/Make.cmd diff --git a/cmd/genkey/genkey.go b/cmd/genkey/genkey.go new file mode 100644 index 0000000..6420306 --- /dev/null +++ b/cmd/genkey/genkey.go @@ -0,0 +1,81 @@ +package main + +import ( + "epoint/dsakey" + "crypto/openpgp" + "log" + "os" + "time" +) + +const usage = "usage: ./genkey name comment email seckeyfile pubkeyfile < seed" + +func serialize(e *openpgp.Entity, sk, pk string) (err error) { + f, err := os.Create(sk) + if err != nil { + return + } + err = e.SerializePrivate(f) + if err != nil { + return + } + err = f.Sync() + if err != nil { + return + } + err = f.Close() + if err != nil { + return + } + // public key + f, err = os.Create(pk) + if err != nil { + return + } + /* + // TODO: maybe Serialize should do this internally + for _, ident := range e.Identities { + err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey) + if err != nil { + return + } + } + for _, subkey := range e.Subkeys { + err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey) + if err != nil { + return + } + } + */ + err = e.Serialize(f) + if err != nil { + return + } + err = f.Sync() + if err != nil { + return + } + err = f.Close() + return +} + +func main() { + if len(os.Args) != 6 { + log.Fatal(usage) + } + b := make([]byte, 1000) + n, err := os.Stdin.Read(b) + if err != nil { + log.Print(err) + log.Fatal(usage) + } + key := dsakey.PrivKey(b[:n]) + e, err := dsakey.NewEntity(key, time.Seconds(), os.Args[1], os.Args[2], os.Args[3]) + if err != nil { + log.Fatal(err) + } + err = serialize(e, os.Args[4], os.Args[5]) + if err != nil { + log.Fatal(err) + } +} diff --git a/dsakey/Makefile b/dsakey/Makefile new file mode 100644 index 0000000..bd29402 --- /dev/null +++ b/dsakey/Makefile @@ -0,0 +1,6 @@ +include $(GOROOT)/src/Make.inc + +TARG=epoint/dsakey +GOFILES=dsakey.go + +include $(GOROOT)/src/Make.pkg diff --git a/dsakey/dsakey.go b/dsakey/dsakey.go new file mode 100644 index 0000000..eb5d129 --- /dev/null +++ b/dsakey/dsakey.go @@ -0,0 +1,106 @@ +package dsakey + +import ( + "crypto/sha1" + "crypto/dsa" + "crypto/openpgp" + "crypto/openpgp/packet" + "crypto/rand" + "crypto" + "fmt" + "io" + "math/big" +) + +const P = "C1773C0DEF5C1D75BA556137CBCE0F6EE534034FCE503D7ED1FF7A27E8638EAC3BD627C734E08D1D828B52C39EB602DC63D9544D1734A981AE2408F8037305B548EFE457E2A79EB511CFF11A0C3DB05CF64971A6AF3EF191D3EBA0841AAAC3BECF4B6CF199EDD59C732BA642A0074BAE1DC3CF724F830930C898B1865F597EF7" +const Q = "DCA9E7C9FDC18CB0B8E9A80E487F96438147EF75" +const G = "502FF28CC4D7BC1100123C9227994341C29773BFBD8D7E8FFED6D87A9D82FE573744AC8E4CCAE93E3A017A6388921CA5B0C9349B249EF87AB30AE01B3C9FD723001CB25E560CA6C25EDFC97613B41346D0597C2ECA2BED7BC6C9A032049B3FFF9AED462D09651A5995DB8E5E111384AC7B62CBAD827009269FC79D3E4E6D8AA3" + +func PrivKey(r []byte) *dsa.PrivateKey { + priv := new(dsa.PrivateKey) + priv.Parameters.P,_ = new(big.Int).SetString(P, 16) + priv.Parameters.Q,_ = new(big.Int).SetString(Q, 16) + priv.Parameters.G,_ = new(big.Int).SetString(G, 16) + + // q > 2^159 prime + // x = sha1(r) + // if x == 0 then x = q - 1 + // if x == q then x = q - 2 + // if x > q then x = x mod q + + x := new(big.Int) + h := sha1.New() + h.Write(r) + x.SetBytes(h.Sum()) + if x.Sign() == 0 { + x.Sub(priv.Q, big.NewInt(1)) + } + switch x.Cmp(priv.Q) { + case 0: + x.Sub(priv.Q, big.NewInt(2)) + case 1: + x.Sub(x, priv.Q) + } + priv.X = x + priv.Y = new(big.Int) + priv.Y.Exp(priv.G, x, priv.P) + return priv +} + +func GenKey() (priv *dsa.PrivateKey, err error) { + x := make([]byte, len(Q)/2) + _, err = io.ReadFull(rand.Reader, x) + priv = PrivKey(x) + return +} + +// NewEntity returns an Entity that contains a fresh DSA private key 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(priv *dsa.PrivateKey, currentTimeSecs int64, name, comment, email string) (e *openpgp.Entity, err error) { + uid := packet.NewUserId(name, comment, email) + if uid == nil { + return nil, fmt.Errorf("NewEntity: invalid argument: user id field contained invalid characters") + } + t := uint32(currentTimeSecs) + e = &openpgp.Entity{ + PrimaryKey: packet.NewDSAPublicKey(t, &priv.PublicKey, false /* not a subkey */ ), + PrivateKey: packet.NewDSAPrivateKey(t, priv, false /* not a subkey */ ), + Identities: make(map[string]*openpgp.Identity), + } + isPrimaryId := true + e.Identities[uid.Id] = &openpgp.Identity{ + Name: uid.Name, + UserId: uid, + SelfSignature: &packet.Signature{ + CreationTime: t, + SigType: packet.SigTypePositiveCert, + PubKeyAlgo: packet.PubKeyAlgoDSA, + 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), + PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true), + 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 +} + diff --git a/dsakey/dsakey_test.go b/dsakey/dsakey_test.go new file mode 100644 index 0000000..9245199 --- /dev/null +++ b/dsakey/dsakey_test.go @@ -0,0 +1,38 @@ +package dsakey + +import ( + "crypto/openpgp" +// "fmt" + "bytes" + "time" + "testing" +) + +func testSignAndVerify(t *testing.T, priv *openpgp.Entity) { + msg := []byte("testing") + w := new(bytes.Buffer) + err := openpgp.DetachSign(w, priv, bytes.NewBuffer(msg)) + if err != nil { + t.Errorf("error signing: %s", err) + return + } + + _, err = openpgp.CheckDetachedSignature(openpgp.EntityList{priv}, bytes.NewBuffer(msg), w) + if err != nil { + t.Errorf("Verify failed") + } +} + +func TestKey(t *testing.T) { + key, err := GenKey() + if err != nil { + t.Errorf("gen dsa key failed: %s", err) + return + } + priv, err := NewEntity(key, time.Seconds(), "a", "b", "c") + if err != nil { + t.Errorf("new entity failed: %s", err) + } else { + testSignAndVerify(t, priv) + } +} -- 2.20.1