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 } // simple key generation for obligation issuer clients func NewIssuerEntity(r []byte, denomination string) (e *openpgp.Entity, err error) { return NewEntity(PrivKey(r), 0, "Issuer", denomination, "") } // simple key generation for obligation holder clients func NewHolderEntity(r []byte, issuer, denomination string) (e *openpgp.Entity, err error) { return NewEntity(PrivKey(r), 0, "Holder of " + issuer, denomination, "") } // check the issuer and denomination associated with the given pgp key func CheckEntity(e *openpgp.Entity) (isIssuer bool, issuer, denomination string, err error) { // TODO: allow non-epoint uids if len(e.Identities) != 1 { err = fmt.Errorf("CheckEntity: expected one identity") return } for _, i := range e.Identities { denomination = i.UserId.Comment if i.UserId.Name == "Issuer" { isIssuer = true issuer = fmt.Sprintf("%X", e.PrimaryKey.Fingerprint) return } prefix := "Holder of " if i.UserId.Name[:len(prefix)] == prefix { issuer = i.UserId.Name[len(prefix):] return } break } err = fmt.Errorf("CheckENtity: invalid userid") return }