橢圓曲線加密解密算法python3實(shí)現(xiàn)

信息安全課程的實(shí)驗(yàn),根據(jù)課件及網(wǎng)上資料,參考實(shí)現(xiàn)

代碼中注釋比較完善,算法的實(shí)現(xiàn)整體流程如下:

- 實(shí)現(xiàn)基本流程:

考慮K=kG ,其中K、G為橢圓曲線Ep(a,b)上的點(diǎn),nG的階(nG=O∞ ),k為小于n的整數(shù)。
則給定kG,根據(jù)加法法則,計(jì)算K很容易但反過來,給定KG,求k就非常困難。
因?yàn)閷?shí)際使用中的ECC原則上把p取得相當(dāng)大,n也相當(dāng)大,要把n個(gè)解點(diǎn)逐一算出來列成上表是不可能的。
這就是橢圓曲線加密算法的數(shù)學(xué)依據(jù)

點(diǎn)G稱為基點(diǎn)(base point

kk<n)為私有密鑰(privte key

K為公開密鑰(public key)


- 代碼實(shí)現(xiàn)(Python3.6)

# -*- coding:utf-8 *-
# author: DYBOY
# time: 2019-3-22 10:12:59
# description: ECC橢圓曲線加密算法實(shí)現(xiàn)
"""
    考慮K=kG ,其中K、G為橢圓曲線Ep(a,b)上的點(diǎn),n為G的階(nG=O∞ ),k為小于n的整數(shù)。
    則給定k和G,根據(jù)加法法則,計(jì)算K很容易但反過來,給定K和G,求k就非常困難。
    因?yàn)閷?shí)際使用中的ECC原則上把p取得相當(dāng)大,n也相當(dāng)大,要把n個(gè)解點(diǎn)逐一算出來列成上表是不可能的。
    這就是橢圓曲線加密算法的數(shù)學(xué)依據(jù)

    點(diǎn)G稱為基點(diǎn)(base point)

    k(k<n)為私有密鑰(privte key)

    K為公開密鑰(public key)
"""


def get_inverse(mu, p):
    """
    獲取y的負(fù)元
    """
    for i in range(1, p):
        if (i*mu)%p == 1:
            return i
    return -1


def get_gcd(zi, mu):
    """
    獲取最大公約數(shù)
    """
    if mu:
        return get_gcd(mu, zi%mu)
    else:
        return zi


def get_np(x1, y1, x2, y2, a, p):
    """
    獲取n*p,每次+p,直到求解階數(shù)np=-p
    """
    flag = 1  # 定義符號(hào)位(+/-)

    # 如果 p=q  k=(3x2+a)/2y1mod p
    if x1 == x2 and y1 == y2:
        zi = 3 * (x1 ** 2) + a  # 計(jì)算分子      【求導(dǎo)】
        mu = 2 * y1    # 計(jì)算分母

    # 若P≠Q(mào),則k=(y2-y1)/(x2-x1) mod p
    else:
        zi = y2 - y1
        mu = x2 - x1
        if zi* mu < 0:
            flag = 0        # 符號(hào)0為-(負(fù)數(shù))
            zi = abs(zi)
            mu = abs(mu)

    # 將分子和分母化為最簡(jiǎn)
    gcd_value = get_gcd(zi, mu)     # 最大公約數(shù)
    zi = zi // gcd_value            # 整除
    mu = mu // gcd_value
    # 求分母的逆元  逆元: ?a ∈G ,ョb∈G 使得 ab = ba = e
    # P(x,y)的負(fù)元是 (x,-y mod p)= (x,p-y) ,有P+(-P)= O∞
    inverse_value = get_inverse(mu, p)
    k = (zi * inverse_value)

    if flag == 0:                   # 斜率負(fù)數(shù) flag==0
        k = -k
    k = k % p
    # 計(jì)算x3,y3 P+Q
    """
        x3≡k2-x1-x2(mod p)
        y3≡k(x1-x3)-y1(mod p)
    """
    x3 = (k ** 2 - x1 - x2) % p
    y3 = (k * (x1 - x3) - y1) % p
    return x3,y3


def get_rank(x0, y0, a, b, p):
    """
    獲取橢圓曲線的階
    """
    x1 = x0             #-p的x坐標(biāo)
    y1 = (-1*y0)%p      #-p的y坐標(biāo)
    tempX = x0
    tempY = y0
    n = 1
    while True:
        n += 1
        # 求p+q的和,得到n*p,直到求出階
        p_x,p_y = get_np(tempX, tempY, x0, y0, a, p)
        # 如果 == -p,那么階數(shù)+1,返回
        if p_x == x1 and p_y == y1:
            return n+1
        tempX = p_x
        tempY = p_y


def get_param(x0, a, b, p):
    """
    計(jì)算p與-p
    """
    y0 = -1
    for i in range(p):
        # 滿足取模約束條件,橢圓曲線Ep(a,b),p為質(zhì)數(shù),x,y∈[0,p-1]
        if i**2%p == (x0**3 + a*x0 + b)%p:
            y0 = i
            break

    # 如果y0沒有,返回false
    if y0 == -1:
        return False

    # 計(jì)算-y(負(fù)數(shù)取模)
    x1 = x0
    y1 = (-1*y0) % p
    return x0,y0,x1,y1


def get_graph(a, b, p):
    """
    輸出橢圓曲線散點(diǎn)圖
    """
    x_y = []
    # 初始化二維數(shù)組
    for i in range(p):
        x_y.append(['-' for i in range(p)])

    for i in range(p):
        val =get_param(i, a, b, p)  # 橢圓曲線上的點(diǎn)
        if(val != False):
            x0,y0,x1,y1 = val
            x_y[x0][y0] = 1
            x_y[x1][y1] = 1

    print("橢圓曲線的散列圖為:")
    for i in range(p):              # i= 0-> p-1
        temp = p-1-i        # 倒序

        # 格式化輸出1/2位數(shù),y坐標(biāo)軸
        if temp >= 10:
            print(temp, end=" ")
        else:
            print(temp, end="  ")

        # 輸出具體坐標(biāo)的值,一行
        for j in range(p):
            print(x_y[j][temp], end="  ")
        print("")   #換行

    # 輸出 x 坐標(biāo)軸
    print("  ", end="")
    for i in range(p):
        if i >=10:
            print(i, end=" ")
        else:
            print(i, end="  ")
    print('\n')


def get_ng(G_x, G_y, key, a, p):
    """
    計(jì)算nG
    """
    temp_x = G_x
    temp_y = G_y
    while key != 1:
        temp_x,temp_y = get_np(temp_x,temp_y, G_x, G_y, a, p)
        key -= 1
    return temp_x,temp_y


def ecc_main():
    while True:
        a = int(input("請(qǐng)輸入橢圓曲線參數(shù)a(a>0)的值:"))
        b = int(input("請(qǐng)輸入橢圓曲線參數(shù)b(b>0)的值:"))
        p = int(input("請(qǐng)輸入橢圓曲線參數(shù)p(p為素?cái)?shù))的值:"))   #用作模運(yùn)算

        # 條件滿足判斷
        if (4*(a**3)+27*(b**2))%p == 0:
            print("您輸入的參數(shù)有誤,請(qǐng)重新輸入!??!\n")
        else:
            break

    # 輸出橢圓曲線散點(diǎn)圖
    get_graph(a, b, p)

    # 選點(diǎn)作為G點(diǎn)
    print("user1:在如上坐標(biāo)系中選一個(gè)值為G的坐標(biāo)")
    G_x = int(input("user1:請(qǐng)輸入選取的x坐標(biāo)值:"))
    G_y = int(input("user1:請(qǐng)輸入選取的y坐標(biāo)值:"))

    # 獲取橢圓曲線的階
    n = get_rank(G_x, G_y, a, b, p)

    # user1生成私鑰,小key
    key = int(input("user1:請(qǐng)輸入私鑰小key(<{}):".format(n)))

    # user1生成公鑰,大KEY
    KEY_x,kEY_y = get_ng(G_x, G_y, key, a, p)

    # user2階段
    # user2拿到user1的公鑰KEY,Ep(a,b)階n,加密需要加密的明文數(shù)據(jù)
    # 加密準(zhǔn)備
    k = int(input("user2:請(qǐng)輸入一個(gè)整數(shù)k(<{})用于求kG和kQ:".format(n)))
    k_G_x,k_G_y = get_ng(G_x, G_y, k, a, p)                         # kG
    k_Q_x,k_Q_y = get_ng(KEY_x, kEY_y, k, a, p)                     # kQ

    # 加密
    plain_text = input("user2:請(qǐng)輸入需要加密的字符串:")
    plain_text = plain_text.strip()
    #plain_text = int(input("user1:請(qǐng)輸入需要加密的密文:"))
    c = []
    print("密文為:",end="")
    for char in plain_text:
        intchar = ord(char)
        cipher_text = intchar*k_Q_x
        c.append([k_G_x, k_G_y, cipher_text])
        print("({},{}),{}".format(k_G_x, k_G_y, cipher_text),end="-")


    # user1階段
    # 拿到user2加密的數(shù)據(jù)進(jìn)行解密
    # 知道 k_G_x,k_G_y,key情況下,求解k_Q_x,k_Q_y是容易的,然后plain_text = cipher_text/k_Q_x
    print("\nuser1解密得到明文:",end="")
    for charArr in c:
        decrypto_text_x,decrypto_text_y = get_ng(charArr[0], charArr[1], key, a, p)
        print(chr(charArr[2]//decrypto_text_x),end="")

        #inverse_value = get_inverse(decrypto_text_x, p)
        #text = charArr[2]*inverse_value%p
        #print(text,end=" ")


if __name__ == "__main__":
    print("*************ECC橢圓曲線加密*************")
    ecc_main()


- 運(yùn)行效果:


- 參考文章:

原文地址:https://blog.dyboy.cn/websecurity/121.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容