椭圆曲线算法(ECC)学习

 转自这里



*本文原创作者:淼淼兮与怀,本文属FreeBuf原创奖励计划,未经许可禁止转载

0x00 前言

椭圆曲线加密算法(ECC) 是基于椭圆曲线数学的一种公钥加密的算法,随着分解大整数方法的进步以及完善、计算机计算速度的提高以及网络的发展,RSA的使用率越来越高.但是为了安全。其密钥的长度一直保守诟病,于是ECC这种新算法逐步走上了现在加密算法的这个大舞台,其使用率和重要性都在逐年上升,那么今天我们就通过这篇文章来介绍一下椭圆曲线加密算法的初认识之数学基础。

150623281619827.jpg

0x01 正文

数学基础1.1椭圆曲线方程

所谓的椭圆曲线指的是一个齐次方程:

深度截图_选择区域_20171202002643.png

数与形结合,所确定的平面曲线.其中系数ai( i=1,2,3····6)定义在某个域上,是有理数域,也可以是无理数域或者复数域、有限域GF(pr),在ECC这个密码体制里用到的都是定义在有限域上的。

一个叫无穷远点的特殊点和椭圆上的所有的点构成一个集合连同一个定义的加法运算构成一个阿贝尔(Abel)群

曲线上的每个点都必须是非奇异的,所谓的"非奇异"或"光滑"的,在数学中是指曲线上任意一点都存在切线。

等式一:

深度截图_选择区域_20171202004128.png

这个等数中我们能看到已知m和P求点Q很容易,反正只知道Q和点P的情况下求m却是非常困难的,这个问题称为离散对数问题中的椭圆曲线上的点群。

我们学的椭圆曲线密码体制就是利用以上的这个困难问题来设计的。

椭圆曲线的形状,并不是椭圆.是因为椭圆曲线的描述方程,类似于计算一个椭圆的周长的方程得名。

数学基础1.2阿贝尔群是什么?

在数学中,群是一种代数结构,由一个集合以及一个二元运算所组成.如果一个集合或者运算是群的话!就必须满足以下条件

封闭性

结合性

单位元

逆元

以及满足数学中的定律交换律:

深度截图_选择区域_20171202010458.png

在椭圆中任取两个点P和点Q,作直线交于椭圆的一点A,过A做y轴的平行线交于另一点B,有一定义

深度截图_选择区域_20171202011022.png

这样,加法的和也在椭圆上,也满足交换律和结合律。

由上文既然Able群是所有点和特殊点的和,若有m个相同的点P相加,记做mP,得到等式一:

深度截图_选择区域_20171202004128.png

深度截图_选择区域_20171202022206.png

数学基础1.3椭圆曲线中的有限域

由上面的介绍,我们已经对椭圆曲线有一定的了解了.但是椭圆是连续的,点和点貌似没有联系如何加密呢?

给出有限域Fq的描述及其元素的表示,q是一个奇素数 或者是2的次方幂.当q奇素数p 时,要求p > 2^191;当q 2的方幂2^m时,要求 m > 192且为素数。

素域Fp:

1q是奇素数p 时,素域Fp中的元素用整数0;1;2; · · · ; p−1表示。

a) 加法单位元是整数0

b) 乘法单位元是整数1

c) 域元素的加法是整数的模p加法,即若a;b   Fp,则a+b = (a+b) mod p

d) 域元素的乘法是整数的模p乘法,即若a;b   Fp,则a · b = (a · b) mod p

2定义在Fp(p是大于3 的素数)上的椭圆曲线方程为:

深度截图_选择区域_20171202014214.png

深度截图_选择区域_20171202014333.png

椭圆曲线E(Fp)定义为:

深度截图_选择区域_20171202014636.png

且满足方程

深度截图_选择区域_20171202020504.png

其中O是无穷远点。

椭圆曲线E(Fp)上的点的数目用#E(Fq)表示,称为椭圆曲线E(Fp) 的阶。

 如果椭圆曲线上一点P,存在最小的正整数n,使得数乘 nP=0∞,则将n称为P的阶,若n 不存在,我们说P是无限阶的。

事实上,在有限域上定义的椭圆曲线上所有的点的阶n都是存在的。

0x02 加密

描述一条Fp上的椭圆曲线,常用到六个参量:T=(p,a,b,n,x,y)。

(p 、a 、b) 用来确定一条椭圆曲线,p为素数域内点的个数,a和b是其内的两个大数;

x,y为G基点的坐标,也是两个大数;

n为点G基点的阶;

以上六个量就可以描述一条椭圆曲线,有时候我们还会用到h(椭圆曲线上所有点的个数p与n相除的整数部分)。

现在我们描述一个利用椭圆曲线进行加密通信的过程:

1、A机器选定一条椭圆曲线 Ep(a,b) 并取椭圆曲线上一点,作为基点G。

2、A机器选择一个私有密钥k,并生成公开密钥 K=kG。

3、A机器将 Ep(a,b) 和点K,G传给用户B。

4、B机器接到信息后 ,将待传输的明文编码到Ep(a,b)上一点M(编码方法很多,这里不作讨论),并产生一个随机整数r。

5、B机器计算

深度截图_选择区域_20171206110725.png

6、B机器将点C1、C2传给A机器。

7、A接到信息后,计算C1-kC2,结果就是点M。因为

深度截图_选择区域_20171206110840.png

再对点M进行解码就可以得到明文。

在这个加密通信中,如果有一个偷窥者H ,他只能看到Ep(a,b)、K、G、C1、C2,而通过K、G 求k 或通过C2、G求r 都是相对困难的,因此,H无法得到A、B间传送的明文信息。

代码实现:

ecies.py

import hashlib

from openssl_wrapper import OpenSSL

from struct import pack, unpack

#1. Generate a ephemeral EC key pair

# we use shortand patent free EC curve in the QR scenerio, which is 'secp160r1'

PUBKEY='02c500146ec52c4fdae22c1c18d81b3679cf70397fdaab8f0014bac0efaff80ce2ec719ba1bcaa53530bf03d6d95'

PRIVKEY='02c500147bd49a3ea78ba2d5a06920f4326e693002419685'

#PUBKEY=PUBKEY.decode('hex')

#PRIVKEY=PRIVKEY.decode('hex')

def gen_ec_keypair(curve='secp112r1'):

    #this function generates EC key pair

    try:

        curve=OpenSSL.curves[curve]

        key = OpenSSL.EC_KEY_new_by_curve_name(curve)

        OpenSSL.EC_KEY_generate_key(key)

        _pubkey_x = OpenSSL.BN_new()

        _pubkey_y = OpenSSL.BN_new()

        _privkey = OpenSSL.EC_KEY_get0_private_key(key)

        _pubkey = OpenSSL.EC_KEY_get0_public_key(key)

        _group = OpenSSL.EC_KEY_get0_group(key)

        OpenSSL.EC_POINT_get_affine_coordinates_GFp(_group, _pubkey, _pubkey_x, _pubkey_y, 0)

        privkey = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(_privkey))

        pubkeyx = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(_pubkey_x))

        pubkeyy = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(_pubkey_y))

        OpenSSL.BN_bn2bin(_privkey, privkey)

        privkey = privkey.raw

        OpenSSL.BN_bn2bin(_pubkey_x, pubkeyx)

        pubkeyx = pubkeyx.raw

        OpenSSL.BN_bn2bin(_pubkey_y, pubkeyy)

        pubkeyy = pubkeyy.raw

        #self.raw_check_key(privkey, pubkeyx, pubkeyy)

        full_privkey=pack('!H', curve) + pack('!H', len(privkey)) + privkey

        full_pubkey=pack('!H', curve) + pack('!H', len(pubkeyx)) + pubkeyx + pack('!H', len(pubkeyy)) + pubkeyy

        return full_privkey, full_pubkey

    finally:

        #release c pointers

        OpenSSL.EC_KEY_free(key)

        OpenSSL.BN_free(_pubkey_x)

        OpenSSL.BN_free(_pubkey_y)

def ecdh_key(a_privkey, b_pubkey):

    #keys should be in binary format

    a_curve=int(a_privkey[0:2].encode('hex'), 16)

    b_curve=int(b_pubkey[0:2].encode('hex'), 16)

    if a_curve != b_curve:

        raise Exception("ECDH Error: Both key must have the save curve type.")

    sx=int(b_pubkey[2:4].encode('hex'), 16)

    sy=int(b_pubkey[4+sx:sx+6].encode('hex'), 16)

    pub_x, pub_y = b_pubkey[4:4+sx], b_pubkey[6+sx:6+sx+sy]

    b_key=OpenSSL.EC_KEY_new_by_curve_name(b_curve)

    _pub_x=OpenSSL.BN_bin2bn(pub_x, sx, 0)

    _pub_y=OpenSSL.BN_bin2bn(pub_y, sy, 0)

    _group=OpenSSL.EC_KEY_get0_group(b_key)

    _pubkey=OpenSSL.EC_POINT_new(_group)

    OpenSSL.EC_POINT_set_affine_coordinates_GFp(_group, _pubkey, _pub_x, _pub_y, 0)

    OpenSSL.EC_KEY_set_public_key(b_key, _pubkey)

    #OpenSSL.EC_KEY_check_key(b_key)

    s=int(a_privkey[2:4].encode('hex'), 16)

    priv=a_privkey[4:4+s]

    a_key=OpenSSL.EC_KEY_new_by_curve_name(a_curve)

    _privkey=OpenSSL.BN_bin2bn(priv, len(priv), 0)

    OpenSSL.EC_KEY_set_private_key(a_key, _privkey)

    #ECDH

    OpenSSL.ECDH_set_method(a_key, OpenSSL.ECDH_OpenSSL())

    ecdh_buf = OpenSSL.malloc(0, s) #computed buffer size should the same as key length

    ecdh_keylen=OpenSSL.ECDH_compute_key(ecdh_buf, s, _pubkey, a_key, 0)

    return ecdh_buf.raw

from Crypto.Cipher import AES

def encrypt(a_privkey, a_pubkey, b_pubkey, content):

    ecdh1=ecdh_key(a_privkey,b_pubkey)

    shared_key=hashlib.md5(ecdh1).digest()   #we need 128 bit key in our QR scenerio

    obj = AES.new(shared_key, AES.MODE_ECB)

    ciphertext = obj.encrypt(content)

    qr=(a_pubkey+ciphertext).encode('base64')

    return qr

def decrypt(b_privkey, qr):

    qr=qr.decode('base64')

    sx=int(qr[2:4].encode('hex'), 16)

    sy=int(qr[4+sx:sx+6].encode('hex'), 16)

    a_pubkey=qr[:6+sx+sy]

    ciphertext=qr[6+sx+sy:]

    ecdh2=ecdh_key(b_privkey,a_pubkey)

    shared_key=hashlib.md5(ecdh2).digest()

    obj = AES.new(shared_key, AES.MODE_ECB)

    content = obj.decrypt(ciphertext)

    return content

a= gen_ec_keypair('secp112r2') #a key is ephemeral, generated everytime

b=gen_ec_keypair('secp112r2')  #in real code, this key pair should come from server, and a client has its public key only

print 'Generated EC pairs for ECDH key exchange:'

print 'Alice -> Private:'+ a[0].encode('hex'), 'Public:' + a[1].encode('hex')

print 'Bob -> Private:' + b[0].encode('hex'), 'Public:' + b[1].encode('hex')

e1= ecdh_key(a[0],b[1])

e2=ecdh_key(b[0],a[1])   #e2 is for server code only

print e1.encode('hex')

print e2.encode('hex')

bm=buffer('Hello there DAI!')

qr= encrypt(a[0],a[1],b[1],bm)

print 'QR code size is', len(qr), ':', qr

#import qrcode

#qrcode.make(qr).show()

#server does the following:

content=decrypt(b[0], qr)

print 'After decryption, content is ', content

openssl_wrapper.py

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import sys

import ctypes

import ctypes.util

OpenSSL = None

class CipherName:

    def __init__(self, name, pointer, blocksize):

        self._name = name

        self._pointer = pointer

        self._blocksize = blocksize

    def __str__(self):

        return "Cipher : " + self._name + " | Blocksize : " + str(self._blocksize) + " | Fonction pointer : " + str(self._pointer)

    def get_pointer(self):

        return self._pointer()

    def get_name(self):

        return self._name

    def get_blocksize(self):

        return self._blocksize

class _OpenSSL:

    """

    Wrapper for OpenSSL using ctypes

    """

    def __init__(self, library):

        """

        Build the wrapper

        """

        self._lib = ctypes.CDLL(library)

        self.pointer = ctypes.pointer

        self.c_int = ctypes.c_int

        self.byref = ctypes.byref

        self.create_string_buffer = ctypes.create_string_buffer

        self.BN_new = self._lib.BN_new

        self.BN_new.restype = ctypes.c_void_p

        self.BN_new.argtypes = []

        self.BN_free = self._lib.BN_free

        self.BN_free.restype = None

        self.BN_free.argtypes = [ctypes.c_void_p]

        self.BN_num_bits = self._lib.BN_num_bits

        self.BN_num_bits.restype = ctypes.c_int

        self.BN_num_bits.argtypes = [ctypes.c_void_p]

        self.BN_bn2bin = self._lib.BN_bn2bin

        self.BN_bn2bin.restype = ctypes.c_int

        self.BN_bn2bin.argtypes = [ctypes.c_void_p, ctypes.c_void_p]

        self.BN_bin2bn = self._lib.BN_bin2bn

        self.BN_bin2bn.restype = ctypes.c_void_p

        self.BN_bin2bn.argtypes = [ctypes.c_void_p, ctypes.c_int,

                                   ctypes.c_void_p]

        self.EC_KEY_free = self._lib.EC_KEY_free

        self.EC_KEY_free.restype = None

        self.EC_KEY_free.argtypes = [ctypes.c_void_p]

        self.EC_KEY_new_by_curve_name = self._lib.EC_KEY_new_by_curve_name

        self.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p

        self.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int]

        self.EC_KEY_generate_key = self._lib.EC_KEY_generate_key

        self.EC_KEY_generate_key.restype = ctypes.c_int

        self.EC_KEY_generate_key.argtypes = [ctypes.c_void_p]

        self.EC_KEY_check_key = self._lib.EC_KEY_check_key

        self.EC_KEY_check_key.restype = ctypes.c_int

        self.EC_KEY_check_key.argtypes = [ctypes.c_void_p]

        self.EC_KEY_get0_private_key = self._lib.EC_KEY_get0_private_key

        self.EC_KEY_get0_private_key.restype = ctypes.c_void_p

        self.EC_KEY_get0_private_key.argtypes = [ctypes.c_void_p]

        self.EC_KEY_get0_public_key = self._lib.EC_KEY_get0_public_key

        self.EC_KEY_get0_public_key.restype = ctypes.c_void_p

        self.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p]

        self.EC_KEY_get0_group = self._lib.EC_KEY_get0_group

        self.EC_KEY_get0_group.restype = ctypes.c_void_p

        self.EC_KEY_get0_group.argtypes = [ctypes.c_void_p]

        self.EC_POINT_get_affine_coordinates_GFp = self._lib.EC_POINT_get_affine_coordinates_GFp

        self.EC_POINT_get_affine_coordinates_GFp.restype = ctypes.c_int

        self.EC_POINT_get_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]

        self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key

        self.EC_KEY_set_private_key.restype = ctypes.c_int

        self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p,

                                                ctypes.c_void_p]

        self.EC_KEY_set_public_key = self._lib.EC_KEY_set_public_key

        self.EC_KEY_set_public_key.restype = ctypes.c_int

        self.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p,

                                               ctypes.c_void_p]

        self.EC_KEY_set_group = self._lib.EC_KEY_set_group

        self.EC_KEY_set_group.restype = ctypes.c_int

        self.EC_KEY_set_group.argtypes = [ctypes.c_void_p, ctypes.c_void_p]

        self.EC_POINT_set_affine_coordinates_GFp = self._lib.EC_POINT_set_affine_coordinates_GFp

        self.EC_POINT_set_affine_coordinates_GFp.restype = ctypes.c_int

        self.EC_POINT_set_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]

        self.EC_POINT_new = self._lib.EC_POINT_new

        self.EC_POINT_new.restype = ctypes.c_void_p

        self.EC_POINT_new.argtypes = [ctypes.c_void_p]

        self.EC_POINT_free = self._lib.EC_POINT_free

        self.EC_POINT_free.restype = None

        self.EC_POINT_free.argtypes = [ctypes.c_void_p]

        self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key

        self.EC_KEY_set_private_key.restype = ctypes.c_int

        self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p,

                                                ctypes.c_void_p]

        self.ECDH_OpenSSL = self._lib.ECDH_OpenSSL

        self._lib.ECDH_OpenSSL.restype = ctypes.c_void_p

        self._lib.ECDH_OpenSSL.argtypes = []

        self.ECDH_set_method = self._lib.ECDH_set_method

        self._lib.ECDH_set_method.restype = ctypes.c_int

        self._lib.ECDH_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p]

        self.ECDH_compute_key = self._lib.ECDH_compute_key

        self.ECDH_compute_key.restype = ctypes.c_int

        self.ECDH_compute_key.argtypes = [ctypes.c_void_p,

                                          ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]

        self.EVP_CipherInit_ex = self._lib.EVP_CipherInit_ex

        self.EVP_CipherInit_ex.restype = ctypes.c_int

        self.EVP_CipherInit_ex.argtypes = [ctypes.c_void_p,

                                           ctypes.c_void_p, ctypes.c_void_p]

        self.EVP_CIPHER_CTX_new = self._lib.EVP_CIPHER_CTX_new

        self.EVP_CIPHER_CTX_new.restype = ctypes.c_void_p

        self.EVP_CIPHER_CTX_new.argtypes = []

        # Cipher

        self.EVP_aes_128_cfb128 = self._lib.EVP_aes_128_cfb128

        self.EVP_aes_128_cfb128.restype = ctypes.c_void_p

        self.EVP_aes_128_cfb128.argtypes = []

        self.EVP_aes_256_cfb128 = self._lib.EVP_aes_256_cfb128

        self.EVP_aes_256_cfb128.restype = ctypes.c_void_p

        self.EVP_aes_256_cfb128.argtypes = []

        self.EVP_aes_128_cbc = self._lib.EVP_aes_128_cbc

        self.EVP_aes_128_cbc.restype = ctypes.c_void_p

        self.EVP_aes_128_cbc.argtypes = []

        self.EVP_aes_256_cbc = self._lib.EVP_aes_256_cbc

        self.EVP_aes_256_cbc.restype = ctypes.c_void_p

        self.EVP_aes_256_cbc.argtypes = []

        # self.EVP_aes_128_ctr = self._lib.EVP_aes_128_ctr

        # self.EVP_aes_128_ctr.restype = ctypes.c_void_p

        # self.EVP_aes_128_ctr.argtypes = []

        # self.EVP_aes_256_ctr = self._lib.EVP_aes_256_ctr

        # self.EVP_aes_256_ctr.restype = ctypes.c_void_p

        # self.EVP_aes_256_ctr.argtypes = []

        self.EVP_aes_128_ofb = self._lib.EVP_aes_128_ofb

        self.EVP_aes_128_ofb.restype = ctypes.c_void_p

        self.EVP_aes_128_ofb.argtypes = []

        self.EVP_aes_256_ofb = self._lib.EVP_aes_256_ofb

        self.EVP_aes_256_ofb.restype = ctypes.c_void_p

        self.EVP_aes_256_ofb.argtypes = []

        self.EVP_bf_cbc = self._lib.EVP_bf_cbc

        self.EVP_bf_cbc.restype = ctypes.c_void_p

        self.EVP_bf_cbc.argtypes = []

        self.EVP_bf_cfb64 = self._lib.EVP_bf_cfb64

        self.EVP_bf_cfb64.restype = ctypes.c_void_p

        self.EVP_bf_cfb64.argtypes = []

        self.EVP_rc4 = self._lib.EVP_rc4

        self.EVP_rc4.restype = ctypes.c_void_p

        self.EVP_rc4.argtypes = []

        self.EVP_CIPHER_CTX_cleanup = self._lib.EVP_CIPHER_CTX_cleanup

        self.EVP_CIPHER_CTX_cleanup.restype = ctypes.c_int

        self.EVP_CIPHER_CTX_cleanup.argtypes = [ctypes.c_void_p]

        self.EVP_CIPHER_CTX_free = self._lib.EVP_CIPHER_CTX_free

        self.EVP_CIPHER_CTX_free.restype = None

        self.EVP_CIPHER_CTX_free.argtypes = [ctypes.c_void_p]

        self.EVP_CipherUpdate = self._lib.EVP_CipherUpdate

        self.EVP_CipherUpdate.restype = ctypes.c_int

        self.EVP_CipherUpdate.argtypes = [ctypes.c_void_p,

                                          ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int]

        self.EVP_CipherFinal_ex = self._lib.EVP_CipherFinal_ex

        self.EVP_CipherFinal_ex.restype = ctypes.c_int

        self.EVP_CipherFinal_ex.argtypes = [ctypes.c_void_p,

                                            ctypes.c_void_p, ctypes.c_void_p]

        self.EVP_DigestInit = self._lib.EVP_DigestInit

        self.EVP_DigestInit.restype = ctypes.c_int

        self._lib.EVP_DigestInit.argtypes = [ctypes.c_void_p, ctypes.c_void_p]

        self.EVP_DigestUpdate = self._lib.EVP_DigestUpdate

        self.EVP_DigestUpdate.restype = ctypes.c_int

        self.EVP_DigestUpdate.argtypes = [ctypes.c_void_p,

                                          ctypes.c_void_p, ctypes.c_int]

        self.EVP_DigestFinal = self._lib.EVP_DigestFinal

        self.EVP_DigestFinal.restype = ctypes.c_int

        self.EVP_DigestFinal.argtypes = [ctypes.c_void_p,

                                         ctypes.c_void_p, ctypes.c_void_p]

        self.EVP_ecdsa = self._lib.EVP_ecdsa

        self._lib.EVP_ecdsa.restype = ctypes.c_void_p

        self._lib.EVP_ecdsa.argtypes = []

        self.ECDSA_sign = self._lib.ECDSA_sign

        self.ECDSA_sign.restype = ctypes.c_int

        self.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p,

                                    ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]

        self.ECDSA_verify = self._lib.ECDSA_verify

        self.ECDSA_verify.restype = ctypes.c_int

        self.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p,

                                      ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]

        self.EVP_MD_CTX_create = self._lib.EVP_MD_CTX_create

        self.EVP_MD_CTX_create.restype = ctypes.c_void_p

        self.EVP_MD_CTX_create.argtypes = []

        self.EVP_MD_CTX_init = self._lib.EVP_MD_CTX_init

        self.EVP_MD_CTX_init.restype = None

        self.EVP_MD_CTX_init.argtypes = [ctypes.c_void_p]

        self.EVP_MD_CTX_destroy = self._lib.EVP_MD_CTX_destroy

        self.EVP_MD_CTX_destroy.restype = None

        self.EVP_MD_CTX_destroy.argtypes = [ctypes.c_void_p]

        self.RAND_bytes = self._lib.RAND_bytes

        self.RAND_bytes.restype = None

        self.RAND_bytes.argtypes = [ctypes.c_void_p, ctypes.c_int]

        self.EVP_sha256 = self._lib.EVP_sha256

        self.EVP_sha256.restype = ctypes.c_void_p

        self.EVP_sha256.argtypes = []

        self.EVP_sha512 = self._lib.EVP_sha512

        self.EVP_sha512.restype = ctypes.c_void_p

        self.EVP_sha512.argtypes = []

        self.HMAC = self._lib.HMAC

        self.HMAC.restype = ctypes.c_void_p

        self.HMAC.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int,

                              ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]

        # self.PKCS5_PBKDF2_HMAC = self._lib.PKCS5_PBKDF2_HMAC

        # self.PKCS5_PBKDF2_HMAC.restype = ctypes.c_int

        # self.PKCS5_PBKDF2_HMAC.argtypes = [ctypes.c_void_p, ctypes.c_int,

        #                                    ctypes.c_void_p, ctypes.c_int,

        #                                    ctypes.c_int, ctypes.c_void_p,

        #                                    ctypes.c_int, ctypes.c_void_p]

        self._set_ciphers()

        self._set_curves()

    def _set_ciphers(self):

        self.cipher_algo = {

            'aes-128-cbc': CipherName('aes-128-cbc', self.EVP_aes_128_cbc, 16),

            'aes-256-cbc': CipherName('aes-256-cbc', self.EVP_aes_256_cbc, 16),

            'aes-128-cfb': CipherName('aes-128-cfb', self.EVP_aes_128_cfb128, 16),

            'aes-256-cfb': CipherName('aes-256-cfb', self.EVP_aes_256_cfb128, 16),

            'aes-128-ofb': CipherName('aes-128-ofb', self._lib.EVP_aes_128_ofb, 16),

            'aes-256-ofb': CipherName('aes-256-ofb', self._lib.EVP_aes_256_ofb, 16),

            #'aes-128-ctr': CipherName('aes-128-ctr', self._lib.EVP_aes_128_ctr, 16),

            #'aes-256-ctr': CipherName('aes-256-ctr', self._lib.EVP_aes_256_ctr, 16),

            'bf-cfb': CipherName('bf-cfb', self.EVP_bf_cfb64, 8),

            'bf-cbc': CipherName('bf-cbc', self.EVP_bf_cbc, 8),

            'rc4': CipherName('rc4', self.EVP_rc4, 128), # 128 is the initialisation size not block size

        }

    def _set_curves(self):

        self.curves = {

            'secp112r1': 704,

            'secp112r2': 705,

            'secp128r1': 706,

            'secp128r2': 707,

            'secp160k1': 708,

            'secp160r1': 709,

            'secp160r2': 710,

            'secp192k1': 711,

            'secp224k1': 712,

            'secp224r1': 713,

            'secp256k1': 714,

            'secp384r1': 715,

            'secp521r1': 716,

            'sect113r1': 717,

            'sect113r2': 718,

            'sect131r1': 719,

            'sect131r2': 720,

            'sect163k1': 721,

            'sect163r1': 722,

            'sect163r2': 723,

            'sect193r1': 724,

            'sect193r2': 725,

            'sect233k1': 726,

            'sect233r1': 727,

            'sect239k1': 728,

            'sect283k1': 729,

            'sect283r1': 730,

            'sect409k1': 731,

            'sect409r1': 732,

            'sect571k1': 733,

            'sect571r1': 734,

            'prime256v1': 415,

        }

    def BN_num_bytes(self, x):

        """

        returns the length of a BN (OpenSSl API)

        """

        return int((self.BN_num_bits(x) + 7) / 8)

    def get_cipher(self, name):

        """

        returns the OpenSSL cipher instance

        """

        if name not in self.cipher_algo:

            raise Exception("Unknown cipher")

        return self.cipher_algo[name]

    def get_curve(self, name):

        """

        returns the id of a elliptic curve

        """

        if name not in self.curves:

            raise Exception("Unknown curve")

        return self.curves[name]

    def get_curve_by_id(self, id):

        """

        returns the name of a elliptic curve with his id

        """

        res = None

        for i in self.curves:

            if self.curves[i] == id:

                res = i

                break

        if res is None:

            raise Exception("Unknown curve")

        return res

    def rand(self, size):

        """

        OpenSSL random function

        """

        buffer = self.malloc(0, size)

        self.RAND_bytes(buffer, size)

        return buffer.raw

    def malloc(self, data, size):

        """

        returns a create_string_buffer (ctypes)

        """

        buffer = None

        if data != 0:

            if sys.version_info.major == 3 and isinstance(data, type('')):

                data = data.encode()

            buffer = self.create_string_buffer(data, size)

        else:

            buffer = self.create_string_buffer(size)

        return buffer

libname = ctypes.util.find_library('crypto')

if libname is None:

    # For Windows ...

    libname = ctypes.util.find_library('libeay32.dll')

if libname is None:

    raise Exception("Couldn't load OpenSSL lib ...")

OpenSSL = _OpenSSL(libname)

python代码下载链接:https://pan.baidu.com/s/1nvbyl3F 密码:02km

0x03 总结

总的来说与传统的大整数分解、离散对数等等难题相似,椭圆曲线也是密码学中的一个难啃的骨头.限于难度,本篇先到这里告一个断落,下期会带来对ECC的深入理解。

*本文原创作者:淼淼兮与怀,本文属FreeBuf原创奖励计划,未经许可禁止转载