123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- 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
- }
- */
|