package curve import ( "context" "errors" "math/big" "git.ali33.ru/fcg-xvii/go-tools/json" ) func NewCrypt(conf json.Map, ctx context.Context) (res *Crypt, err error) { var p *big.Int var check bool if conf.KeyExists("p") { p, check = big.NewInt(0).SetString(conf.String("p", ""), 10) if !check { return nil, errors.New(`ожидается строка числового значения p > 0 в поле [ p ], например "1234"`) } if p.Cmp(intZero) <= 0 { return nil, errors.New(`ожидается строка числового значения p > 0 в поле [ p ], например "1234"`) } } res = new(Crypt) err = res.Init(p, ctx) return } type Crypt struct { p *big.Int g *big.Int } func (s *Crypt) IsValid() bool { return s.p != nil } func (s *Crypt) Init(p *big.Int, ctx context.Context) (err error) { if s.p != nil { return errors.New("параметры криптографии инициированы были инициализированы ранее") } if p == nil { //p = Random(valMin, max) p = Random(valMin, maxTest) } s.p, s.g, err = SearchP(p, ctx) return } func (s *Crypt) Keys(key *big.Int, ctx context.Context) *KeyPair { if !s.IsValid() { s.Init(nil, ctx) } priv := &KeyPrivate{ key: key, c: s, } pub := &KeyPublic{ key: Exp(s.g, priv.key, s.p), c: s, } res := &KeyPair{ priv: priv, pub: pub, } return res } func (s *Crypt) KeysGenerate(ctx context.Context) *KeyPair { return s.Keys(Random(big.NewInt(1), Sub64(s.p, 1)), ctx) } func (s *Crypt) BrutforceKey(pub *KeyPublic, threads int, ctx context.Context) (res *KeyPair, err error) { if threads < 0 { threads = 1 } else if threads > 5 { threads = 5 } ch := make(chan *KeyPair) cctx, cancel := context.WithCancel(ctx) parts := Split(s.p, threads, big.NewInt(1), big.NewInt(1)) for i := 0; i < threads; i++ { go func(part []*big.Int) { cur, finish := intCopy(part[0]), part[1] for { select { case <-cctx.Done(): return case <-ctx.Done(): return default: if cur.Cmp(finish) <= 0 { pair := s.Keys(cur, ctx) if pair.pub.IsEqual(pub) { ch <- pair return } cur = Add64(cur, 1) } else { return } } } }(parts[i]) } defer cancel() select { case res = <-ch: case <-ctx.Done(): err = errors.New("Атака грубой силы не удалась - время вышло") } return } ////////////////////////////// type KeyPair struct { priv *KeyPrivate pub *KeyPublic } type KeyPrivate struct { key *big.Int c *Crypt } func (s *KeyPrivate) MessageDecode(mes *Message) ([]byte, error) { sl := Exp(mes.a, s.key, s.c.p) if sl.ModInverse(sl, s.c.p) == nil { return nil, errors.New("Ощиюбка расшифровки сообщения: некорректный приватный ключ") } data := make([]byte, len(mes.encrypted)) for i, e := range mes.encrypted { part := Mul(sl, e) data[i] = Mod(part, s.c.p).Bytes()[0] } return data, nil } type KeyPublic struct { key *big.Int c *Crypt } func (s *KeyPublic) IsEqual(c *KeyPublic) bool { return s.key.Cmp(c.key) == 0 } func (s *KeyPublic) MessageEncode(data []byte) (res *Message) { k := Random(big.NewInt(1), Sub64(s.c.p, 20)) k = SearchPrime(k) //k := big.NewInt(2) res = &Message{ a: Exp(s.c.g, k, s.c.p), encrypted: make([]*big.Int, len(data)), } sl := Exp(s.key, k, s.c.p) for i, b := range data { part := Mul(sl, big.NewInt(int64(b))) res.encrypted[i] = Mod(part, s.c.p) } return } ////////////////////////////// type Message struct { a *big.Int encrypted []*big.Int } /* // PublicKey represents an ElGamal public key. type PublicKey struct { G, P, Y *big.Int } // PrivateKey represents an ElGamal private key. type PrivateKey struct { PublicKey X *big.Int } // Encrypt encrypts the given message to the given public key. The result is a // pair of integers. Errors can result from reading random, or because msg is // too large to be encrypted to the public key. func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) { pLen := (pub.P.BitLen() + 7) / 8 log.Println(pLen, len(msg)) if len(msg) > pLen-11 { err = errors.New("elgamal: message too long") return } // EM = 0x02 || PS || 0x00 || M em := make([]byte, pLen-1) em[0] = 2 ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] err = nonZeroRandomBytes(ps, random) if err != nil { return } em[len(em)-len(msg)-1] = 0 copy(mm, msg) m := new(big.Int).SetBytes(em) k, err := rand.Int(random, pub.P) if err != nil { return } log.Println("Y", pub.Y) c1 = new(big.Int).Exp(pub.G, k, pub.P) s := new(big.Int).Exp(pub.Y, k, pub.P) c2 = s.Mul(s, m) c2.Mod(c2, pub.P) return } // Decrypt takes two integers, resulting from an ElGamal encryption, and // returns the plaintext of the message. An error can result only if the // ciphertext is invalid. Users should keep in mind that this is a padding // oracle and thus, if exposed to an adaptive chosen ciphertext attack, can // be used to break the cryptosystem. See “Chosen Ciphertext Attacks // Against Protocols Based on the RSA Encryption Standard PKCS #1”, Daniel // Bleichenbacher, Advances in Cryptology (Crypto '98), func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { s := new(big.Int).Exp(c1, priv.X, priv.P) if s.ModInverse(s, priv.P) == nil { return nil, errors.New("elgamal: invalid private key") } s.Mul(s, c2) s.Mod(s, priv.P) em := s.Bytes() firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) // The remainder of the plaintext must be a string of non-zero random // octets, followed by a 0, followed by the message. // lookingForIndex: 1 iff we are still looking for the zero. // index: the offset of the first zero byte. var lookingForIndex, index int lookingForIndex = 1 for i := 1; i < len(em); i++ { equals0 := subtle.ConstantTimeByteEq(em[i], 0) index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) } if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { return nil, errors.New("elgamal: decryption error") } return em[index+1:], nil } // nonZeroRandomBytes fills the given slice with non-zero random octets. func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { _, err = io.ReadFull(rand, s) if err != nil { return } for i := 0; i < len(s); i++ { for s[i] == 0 { _, err = io.ReadFull(rand, s[i:i+1]) if err != nil { return } } } return } */