[山海关crypto 训练营 day6]

日常鼓励自己:成功的关键,在于勇敢承担责任。

Smooth Criminal(60 pt)

题目描述

在这里插入图片描述简单ecc入门题目

题目源代码和相关数据

from Crypto.Cipher import AES
from Crypto.Util.number import inverse
from Crypto.Util.Padding import pad, unpad
from collections import namedtuple
from random import randint
import hashlib
import os

# Create a simple Point class to represent the affine points.
Point = namedtuple("Point", "x y")

# The point at infinity (origin for the group law).
O = 'Origin'

FLAG = b'crypto{??????????????????????????????}'


def check_point(P: tuple):
    if P == O:
        return True
    else:
        return (P.y**2 - (P.x**3 + a*P.x + b)) % p == 0 and 0 <= P.x < p and 0 <= P.y < p


def point_inverse(P: tuple):
    if P == O:
        return P
    return Point(P.x, -P.y % p)


def point_addition(P: tuple, Q: tuple):
    # based of algo. in ICM
    if P == O:
        return Q
    elif Q == O:
        return P
    elif Q == point_inverse(P):
        return O
    else:
        if P == Q:
            lam = (3*P.x**2 + a)*inverse(2*P.y, p)
            lam %= p
        else:
            lam = (Q.y - P.y) * inverse((Q.x - P.x), p)
            lam %= p
    Rx = (lam**2 - P.x - Q.x) % p
    Ry = (lam*(P.x - Rx) - P.y) % p
    R = Point(Rx, Ry)
    assert check_point(R)
    return R


def double_and_add(P: tuple, n: int):
    # based of algo. in ICM
    Q = P
    R = O
    while n > 0:
        if n % 2 == 1:
            R = point_addition(R, Q)
        Q = point_addition(Q, Q)
        n = n // 2
    assert check_point(R)
    return R


def gen_shared_secret(Q: tuple, n: int):
    # Bob's Public key, my secret int
    S = double_and_add(Q, n)
    return S.x


def encrypt_flag(shared_secret: int):
    # Derive AES key from shared secret
    sha1 = hashlib.sha1()
    sha1.update(str(shared_secret).encode('ascii'))
    key = sha1.digest()[:16]
    # Encrypt flag
    iv = os.urandom(16)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = cipher.encrypt(pad(FLAG, 16))
    # Prepare data to send
    data = {}
    data['iv'] = iv.hex()
    data['encrypted_flag'] = ciphertext.hex()
    return data


# Define the curve
p = 310717010502520989590157367261876774703
a = 2
b = 3

# Generator
g_x = 179210853392303317793440285562762725654
g_y = 105268671499942631758568591033409611165
G = Point(g_x, g_y)

# My secret int, different every time!!
n = randint(1, p)

# Send this to Bob!
public = double_and_add(G, n)
print(public)

# Bob's public key
b_x = 272640099140026426377756188075937988094
b_y = 51062462309521034358726608268084433317
B = Point(b_x, b_y)

# Calculate Shared Secret
shared_secret = gen_shared_secret(B, n)

# Send this to Bob!
ciphertext = encrypt_flag(shared_secret)
print(ciphertext)

#Point(x=280810182131414898730378982766101210916, y=291506490768054478159835604632710368904)

#{'iv': '07e2628b590095a5e332d397b8a59aa7', 'encrypted_flag': '8220b7c47b36777a737f5ef9caa2814cf20c1c1ef496ec21a9b4833da24a008d0870d3ac3a6ad80065c138a2ed6136af'}

根据题目代码分析,借助ecc进行密码传输。并且以传输的秘密的哈希值的前十六位作为密钥加密flag,我们可以得到共享的秘密,获得加密的密钥,解密获得flag

本题属于ECC的基础性题目,接着这个题目将ECC的相关知识整理一下:

ECC基础知识

简单介绍

椭圆曲线密码学(Elliptic Curve Cryptography),是一种基于椭圆曲线上的离散对数困难问题(ECDLP)的公钥密码体制,其优势是可以使用较短长度的密钥达到与其他公钥密码体制相当的安全性,160bit的ecc大概相当于1024bit的RSA的密码强度。

最著名的椭圆曲线:
bitcoin中用作数字签名的椭圆曲线secp256k1: y 2 = x 3 + 7 y^2=x^3+7 y2=x3+7

相关计算

相关图片引用自知乎

加法运算

过曲线上的两点A、B画一条直线,找到直线与椭圆曲线的交点,交点关于x轴对称位置的点,定义为A+B,即为加法。如下图所示:A + B = C
在这里插入图片描述

倍点计算

上述方法无法解释A + A,即两点重合的情况,因此在这种情况下,将椭圆曲线在A点的切线,与椭圆曲线的交点,交点关于x轴对称位置的点,定义为A + A,即2A,即为二倍运算。
在这里插入图片描述

斜率计算

1.若 P = Q P=Q P=Q, k = ( 3 x 2 2 + a ) / 2 y 1 k=(3x_2^2+a)/2y_1 k=(3x22+a)/2y1
2.若 P ≠ Q P \neq Q P=Q, k = ( y 2 − y 1 ) / ( x 2 − x 1 ) k=(y_2-y_1)/(x_2-x_1) k=(y2y1)/(x2x1)

加法计算

P + Q = R , P ( x 1 , y 1 ) , Q ( x 2 , y 2 ) , R ( x 3 , y 3 ) P+Q=R,P(x_1,y_1),Q(x_2,y_2),R(x_3,y_3) P+Q=R,P(x1,y1),Q(x2,y2),R(x3,y3)
x 3 ≡ k 2 − x 1 − x 2   m o d   ( p ) y 3 ≡ k ( x 1 − x 3 ) − y 1   m o d   ( p ) x_3 \equiv k^2-x_1-x_2 \ mod \ (p) \\ y_3 \equiv k(x_1-x_3)-y_1\ mod \ (p) x3k2x1x2 mod (p)y3k(x1x3)y1 mod (p)

ecc加解密计算

选取椭圆曲线上一点 G G G,选取随机数 k k k,则 K = k ∗ G K=k*G K=kG,公开 K K K作为公钥,妥善保存随机数 k k k作为自己的私钥,在已知 k , G k,G k,G的前提下根据加分计算很容易得到 K K K,但是在已知 K , G K,G K,G的前提下求解 k k k是一个很困难的问题。
公钥加密: 选择随机数 r r r,将消息 M M M生成密文对 C C C, C = { r G , M + r K } C=\{rG,M+rK\} C={rG,M+rK}
私钥解密: C 2 − k ∗ C 1 = M + r K − k ∗ r G = M + r ∗ k G − k ∗ r G = M C_2-k*C_1=M+rK-k*rG=M+r*kG-k*rG=M C2kC1=M+rKkrG=M+rkGkrG=M

ecc数字签名(ECDSA)

椭圆曲线签名算法(ECDSA)。设私钥、公钥分别为d,Q,即 Q = d G Q=dG Q=dG,其中 G G G为基点。
私钥签名:
1.选择随机数 r r r,计算 r ∗ G ( x , y ) r*G(x,y) rG(x,y)
2.根据选定的随机数 r r r,消息 M M M的哈希值 h h h,私钥 d d d,计算 s = ( h + d x ) / r s=(h+dx)/r s=(h+dx)/r
3.将消息 M M M,和签名 { r G , s } \{rG,s\} {rG,s}发送给接收方
公钥验证:
1.接收方收到消息 M M M,以及 { r G , s } \{rG,s\} {rG,s}
2.根据消息 M M M,计算消息的哈希值 h h h
3.使用发送方公钥 Q Q Q计算: h G / s + x Q / s hG/s+xQ/s hG/s+xQ/s,并与 r G rG rG比较,如果相等则签名验证成功。
原理: h G / s + x Q / s = h G / s + x ( d G ) / s = ( h + x d ) G / s = r ( h + x d ) G / ( h + d x ) = r G hG/s + xQ/s = hG/s + x(dG)/s = (h+xd)G/s = r(h+xd)G / (h+dx) = rG hG/s+xQ/s=hG/s+x(dG)/s=(h+xd)G/s=r(h+xd)G/(h+dx)=rG

题目分析

回到这个题目, 根据题目名字猜测考察内容为光滑椭圆曲线。
通过代码验证:

p = 310717010502520989590157367261876774703
a = 2
b = 3

E=EllipticCurve(GF(p),[a,b])

# Generator
g_x = 179210853392303317793440285562762725654
g_y = 105268671499942631758568591033409611165
G = E.point((g_x, g_y))

n=G.order()
fac=list(factor(n))
print(fac)

#[(2, 1), (3, 7), (139, 1), (165229, 1), (31850531, 1), (270778799, 1), (179317983307, 1)]

验证发现,椭圆曲线的阶确实可以被分解。
这里直接使用Pohlig-Hellman算法

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib

# Define the curve
p = 310717010502520989590157367261876774703
a = 2
b = 3

E=EllipticCurve(GF(p),[a,b])

# Generator
g_x = 179210853392303317793440285562762725654
g_y = 105268671499942631758568591033409611165
G = E.point((g_x, g_y))

# Bob's public key
b_x = 272640099140026426377756188075937988094
b_y = 51062462309521034358726608268084433317
QB = E.point((b_x, b_y))

#Alice's public key
a_x=280810182131414898730378982766101210916
a_y=291506490768054478159835604632710368904
QA=E.point((a_x,a_y))

#order of generator
n=G.order()

#factoring order! --> proves E is a smooth curve mod p
fac=list(factor(n))

moduli=[]
remainder=[]

#solving dlp using pohlig-hellman algorithm
for i,j in fac:
	mod=i**j
	_g_=G*ZZ(n/mod)
	_q_=QA*ZZ(n/mod)

	dl=discrete_log(_q_,_g_,operation="+")
	moduli.append(mod)
	remainder.append(dl)
	#print(dl)

#Alice's secret integer
nA=crt(remainder,moduli)

#shared secret
S=QB*nA

#key for AES
sha1 = hashlib.sha1()
sha1.update(str(S[0]).encode('ascii'))
key = sha1.digest()[:16]

iv=bytes.fromhex('07e2628b590095a5e332d397b8a59aa7')
enc=bytes.fromhex('8220b7c47b36777a737f5ef9caa2814cf20c1c1ef496ec21a9b4833da24a008d0870d3ac3a6ad80065c138a2ed6136af')

#AES object
cipher=AES.new(key,AES.MODE_CBC,iv)
flag=unpad(cipher.decrypt(enc),16).decode()

#output
print(flag)
#crypto{n07_4ll_curv3s_4r3_s4f3_curv3s}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值