0x4a52466c696e74 2 years ago
parent
commit
96fa4d75ac
5 changed files with 237 additions and 100 deletions
  1. BIN
      __pycache__/crypt.cpython-38.pyc
  2. BIN
      __pycache__/point.cpython-38.pyc
  3. 48 0
      crypt.py
  4. 163 90
      curve.py
  5. 26 10
      point.py

BIN
__pycache__/crypt.cpython-38.pyc


BIN
__pycache__/point.cpython-38.pyc


+ 48 - 0
crypt.py

@@ -0,0 +1,48 @@
+# pycrypto необходим для AES
+# pip3 install pycrypto
+
+from Crypto.Cipher import AES
+import base64
+
+# Выравнивание шифруемой строки
+def paddingSetup(text):
+    nLength = 16 - (len(text.encode('utf-8')) % 16)
+    text += chr(nLength) * nLength
+    return text
+
+
+# Удаление символов выравнивания
+def paddingRemove(text):
+    textLen = len(text)
+    if textLen == 0:
+        return text
+    asc = ord(text[-1])
+    if asc >= 16:
+        return text
+    return text[0:-asc]
+
+# Алгоритм симметричного шифрования AES
+# Ключем шифрования является точка секрета, полученная из приватного и публичного ключа
+class CipherAES:
+
+    def __init__(self, curve, secretPoint):
+        # в качестве ключа используется хэш точки секрета
+        self.key = secretPoint.md5()
+        # в качестве инициализирующего вектора - урезанный хэш базовой точки подгруппы эллиптической кривой
+        self.iv = curve.g.md5()
+
+    # инициализация шировальщика
+    def cipher(self):
+        return AES.new(key=self.key, mode=AES.MODE_CBC, IV=self.iv)
+
+    # Шифровка сообщения    
+    def encrypt(self, text):
+        data = self.cipher().encrypt(paddingSetup(text))
+        return str(base64.b64encode(data), 'utf-8')
+
+    # Расшифровка сообщения
+    def decrypt(self, encryptedText):
+        data = base64.b64decode(encryptedText)
+        bytes = self.cipher().decrypt(data)
+        blank = str(bytes, 'utf-8').strip()
+        return paddingRemove(blank)

+ 163 - 90
curve.py

@@ -1,28 +1,17 @@
 import random, sympy
 from point import Point
+from crypt import CipherAES
+from tools import searchPrime
 
-'''
-'secp256k1',
-p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
-a=0,
-b=7,
-g=(0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8),
-# Subgroup order.
-n=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
-# Subgroup cofactor.
-h=1,
-'''
-
-# y2 = x3 + ax + b
 class Curve:
     
-    def __init__(self, p, a, b, gx, gy, n, h):
+    def __init__(self, p, a, b, gx = None, gy = None, n = None, h = 1):
         # размер конечного поля
         self.p = p
         # коэффиценты уравнения a и b
         self.a = a
         self.b = b
-        # базовая точка
+        # базовая точка, определяющая подгруппу
         self.g = Point(
             curve = self,
             x = gx,
@@ -33,30 +22,58 @@ class Curve:
         # кофактор подгруппы
         self.h = h
 
+    def clear(self):
+        self.g = self.n = None
+
     def isSingular(self):
         res = 4 * self.a ** 3 + 27 * self.b ** 2 == 0
         return res
 
+    # Поиск порядка 
     def setupN(self):
-        for self.n in range(self.p - 1, 1, -1):
-            if sympy.isprime(self.n):
+        dx, dy = self.g.x, (-1 * self.g.y) % self.p
+        tmpG = self.g.copy()
+        self.n = 1
+        while True:
+            self.n += 1
+            tmpG = tmpG + self.g
+            if tmpG.x == dx and tmpG.y == dy:
+                self.n += 1
                 return
 
-    def setupG(self, processCallback = None):
-        percent = 0
-        for x in range(self.n, 0, -1):
-            if processCallback is not None:
-                dPercent = round(100 - x * 100 / self.n, 5)
-                if dPercent != percent:
-                    percent = dPercent
-                    processCallback(percent)
-            p1, p2 = self.pointsCurve(x)
-            if p1.isInCurve():
-                self.g = p1
-                #print(p1.coords(), p1.isInCurve())
-                #print(p2.coords(), p2.isInCurve())
+    # Выбор и установка случайной точки g
+    def setupGAuto(self):
+        x = random.randrange(1, self.p - 1)
+        p1, p2 = self.searchClosePoints(x)
+        if p1.isInCurve():
+            self.g = p1
+        elif p2.isInCurve():
+            self.g = p2
+    
+    # Поиск близлежащих точек по x
+    def searchClosePoints(self, x):
+        if x >= self.p:
+            x = self.p - 1
+        if x < 0:
+            x = 0
+        kx = x
+        while True:
+            if x >= self.p and kx < 0:
+                return self.point()
+            # Поиск вправо
+            if x <= self.p:
+                p1, p2 = self.pointsCurve(x)
+                if p1.isInCurve():
+                    return p1, p2
+                x += 1
+            # Поиск влево
+            if kx <= 0:
+                p1, p2 = self.pointsCurve(kx)
+                if p1.isInCurve():
+                    return p1, p2
+                kx -= 1
+        return self.point()
 
-                return
 
     def point(self, x = None, y = None):
         return Point(
@@ -91,7 +108,7 @@ class Curve:
     # Обратное деление по модулю p кривой
     def inverseMod(self, k, point):
         if k == 0:
-            raise ZeroDivisionError('division by zero')
+            raise ZeroDivisionError('Деление на 0 невозможно!!!')
         if k < 0:
             # k ** -1 = p - (-k) ** -1  (mod p)
             return point - self.inverseMod(-k, point)
@@ -105,71 +122,127 @@ class Curve:
             old_s, s = s, old_s - quotient * s
             old_t, t = t, old_t - quotient * t
         gcd, x, y = old_r, old_s, old_t
-        #assert gcd == 1
-        #assert (k * x) % p == 1
         return x % point
 
     def randomKeypair(self):
-        keyPriv = random.randrange(1, self.n)
+        keyPriv = random.randrange(1, self.n - 1)
+        print(keyPriv)
+        keyPub = self.g * keyPriv
+        return keyPriv, keyPub
+
+    def keypair(self, keyPriv):
         keyPub = self.g * keyPriv
         return keyPriv, keyPub
 
+    # Создание публичного ключа из приватного
     def keyPub(self, keyPriv):
+        # Результат - умножение точки подгруппы на приватный ключ
         return self.g * keyPriv
 
+    # Вычисление общего секретного ключа, по которому производится шифрование и расшифровка сообщений
+    def pointSecret(self, myKeyPrivate, friendKeyPublic):
+        return friendKeyPublic * myKeyPrivate
+
+    # Шифровка сообщения секретным ключем
+    def encodeMessage(self, secretPoint, text):
+        cipher = CipherAES(self, secretPoint)
+        return cipher.encrypt(text)
+
+    # Расшифровка сообщения секретным ключем
+    def decodeMessage(self, secretPoint, encodedText):
+        cipher = CipherAES(self, secretPoint)
+        return cipher.decrypt(encodedText)
+        
+
 #################################
-'''
-c = Curve(
-    p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
-    a = 0,
-    b = 7,
-    gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
-    gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
-    n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
-    h = 1
-)
-
-c = Curve(
-    p = 6277101735386680763835789423207666416083908700390324961279,
-    a = -3,
-    b = 2455155546008943817740293915197451784769108058161191238065,
-    gx = 602046282375688656758213480587526111916698976636884684818,
-    gy = 174050332293622031404857552280219410364023488927386650641,
-    n = 6277101735386680763835789423176059013767194773182842284081,
-    h = 1
-)
-'''
-
-c = Curve(
-    p = 2 ** 20,
-    a = 5,
-    b = 4,
-    gx = 2,
-    gy = 2,
-    n = 54534432,
-    h = 1
-)
-
-if c.isSingular():
-    print('Кривая сингулярна')
-    exit(0)
-
-def process(percent):
-    print(percent)
-
-c.setupN()
-c.setupG(process)
-print(c.n)
-
-aPriv, aPub = c.randomKeypair()
-bPriv, bPub = c.randomKeypair()
-
-print(hex(aPriv))
-print(aPub.show())
-
-#aS = scalar_mult(alice_private_key, bob_public_key)
-aS = bPub * aPriv
-bS = aPub * bPriv
-
-print(aS.show())
-print(bS.show())
+
+# Тестирование
+if __name__ == '__main__':
+
+    # Создание объекта эллиптической кривой (кривая из исходников openssl)
+    '''
+    cur = Curve(
+        # Размер конечного поля
+        p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
+        # Коэффиценты
+        a = 0,
+        b = 7,
+        # Координаты точки, определяющей подгруппу
+        gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
+        gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
+        # Размер подгруппы
+        n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
+        # Кофактор подгруппы
+        h = 1
+    )
+    '''
+    cur = Curve(
+        p = searchPrime(2 ** 18),
+        a = 1550,
+        b = 7840
+    )
+
+    print('setup g')
+    cur.setupGAuto()
+    print('g', cur.g.coords(), cur.g.isInCurve())
+    print('setup n')
+    cur.setupN()
+    print(cur.p, cur.n)
+
+    print(cur.n, cur.g.coords(), cur.g.isInCurve())
+
+    k1, p1 = cur.keypair(10)
+    print(k1, p1.coords())
+
+    k2, p2 = cur.keypair(110)
+    print(k2, p2.coords())
+
+    #exit(0)
+
+    # В зашифрованном обмене данными принимают участие 2 пользователя.
+    # Далее - п1 (пользователь 1) и п2 (пользователь 2)
+
+    # Каждый из пользовательей должен создать свою пару ключей (приватный и публичный) исходя из параметров одной эллиптической кривой
+
+    # Создание пары ключей п1
+    p1KeyPriv, p1KeyPub = cur.randomKeypair()
+    # Создание пары ключей п2
+    p2KeyPriv, p2KeyPub = cur.randomKeypair()
+
+    # Предположим, что п1 и п2 обменялись публичными ключами
+    # Далее каждый из них может рассчитать общий секретный ключ, используя свой приватный ключ и полученный публичный ключ контрагента
+    # Секретный ключ идентичен для п1 и п2 и используется в качестве ключа в алгоритме симметричного шифрования, который используется
+    # для шифровки и расшифровки сообщений
+    
+    # Расчет секретного ключа п1
+    p1KeySecret = cur.pointSecret(p1KeyPriv, p2KeyPub)
+    print(p1KeySecret.coords())
+
+    # Расчет секретного ключа п2
+    p2KeySecret = cur.pointSecret(p2KeyPriv, p1KeyPub)
+    print(p2KeySecret.coords())
+
+    # Покажем, что полученные секретные ключи идентичны у п1 и п2
+    print(p1KeySecret.isEqual(p2KeySecret))
+
+    #exit(0)
+
+    # Далее п1 отправляет зашифрованное сообщение п2
+    p1MessageEncrypted = cur.encodeMessage(p1KeySecret, 'Привет, как дела?')
+    #Покажем зашифрованное сообщение
+    print("п1: ", p1MessageEncrypted)
+
+    # п2 расшифровывает полученное сообщение
+    p1MessageDecrypted = cur.decodeMessage(p2KeySecret, p1MessageEncrypted)
+    # Покажем расшифрованное сообщение
+    print("п1: ", p1MessageDecrypted)
+
+    # п2 отправляет зашифрованным сообщением п1
+    p2MessageEncrypted = cur.encodeMessage(p2KeySecret, 'Спасибо, у меня всё хорошо :)')
+    #Покажем зашифрованное сообщение
+    print("п2: ", p2MessageEncrypted)
+
+    # п1 расшифровывает полученное сообщение
+    p2MessageDecrypted = cur.decodeMessage(p1KeySecret, p2MessageEncrypted)
+    # Покажем расшифрованное сообщение
+    print("п2: ", p2MessageDecrypted)

+ 26 - 10
point.py

@@ -1,3 +1,4 @@
+import hashlib
 
 class Point:
 
@@ -7,7 +8,7 @@ class Point:
         self.x = x
         self.y = y
 
-    # Копирование точки
+    # Копирование объекта точки
     def copy(self):
         return Point(
             curve = self.curve,
@@ -15,11 +16,13 @@ class Point:
             y = self.y,
         )
 
+    # HEX формат строки с координатами
     def show(self):
         if self.isNone():
             return "None"
         return "(0x{:x}, 0x{:x})".format(self.x, self.y)
 
+    # Числовой формат строки с координатами
     def showCoords(self):
         if self.isNone():
             return "None"
@@ -33,7 +36,7 @@ class Point:
             y = y
         )
 
-    # Иницуиализация новой точки с неопределенными координатами
+    # Инициализация новой точки с неопределенными координатами
     def pointNull(self):
         return Point(
             x = None,
@@ -42,7 +45,7 @@ class Point:
         )
 
     # Проверка, определена ли точка.
-    # ТОчка считается неопределенной, если одна из координат или кривая не определены
+    # Точка считается неопределенной, если одна из координат или объект эллиптической кривой не определены
     def isNone(self):
         return self.x is None or self.y is None or self.curve is None
 
@@ -50,7 +53,7 @@ class Point:
     def coords(self):
         return self.x, self.y
 
-    # Проверка пренадлежности точки к кривой
+    # Проверка пренадлежности точки к эллиптической кривой
     def isInCurve(self):
         if self.isNone():
             return False
@@ -65,7 +68,7 @@ class Point:
         x1, y1 = self.coords()
         x2, y2 = point.coords()
         if self.x == point.x:
-            # точки равны.
+            # точки равны
             c = self.curve
             m = (3 * x1 * x1 + cur.a) * cur.inverseMod(2 * y1, cur.p)
         else:
@@ -73,10 +76,8 @@ class Point:
             m = (y1 - y2) * cur.inverseMod(x1 - x2, cur.p)
         return m
 
-    # Сложение
+    # Скалярное сложение точек
     def __add__(self, point):
-        #assert is_on_curve(point1)
-        #assert is_on_curve(point2)
         if self.isNone():
             return point.copy()
         if point.isNone():
@@ -108,7 +109,6 @@ class Point:
 
     # Умножение
     def __mul__(self, k):
-        #assert is_on_curve(point)
         if self.isNone() or k % self.curve.n == 0:
             return self.pointNull()
 
@@ -126,7 +126,23 @@ class Point:
             # Double.
             addend = addend + addend
             k >>= 1
-        #assert is_on_curve(result)
         return res
 
+    # Вычисление хэша точки (числовая строка суммы координат)
+    def md5(self):
+        src = str(self.x + self.y)
+        return hashlib.md5(src.encode('utf-8')).digest()
+
+    # Вычисление хэша по оси x
+    def md5X(self):
+        return hashlib.md5(str(self.x).encode('utf-8')).digest()
     
+    # Вычисление хэша по оси y
+    def md5Y(self):
+        return hashlib.md5(str(self.y).encode('utf-8')).digest()
+
+    # Проверка совпадения координат 2х точек по осям x и y
+    def isEqual(self, point):
+        x1, y1 = self.coords()
+        x2, y2 = point.coords()
+        return x1 == x2 and y1 == y2