椭圆曲线密码学(ECC)之Secp256k1
   软件工程   1 评论   1789 浏览

椭圆曲线密码学(ECC)之Secp256k1

   软件工程   1 评论   1789 浏览

椭圆曲线数字签名算法(ECDSA)是椭圆曲线数学的一种公钥密码的算法,安全性高、处理速度快、存储空间占用小。其优点与RSA相比毋庸置疑。作为区块链的关键加密技术,也是阿里云盘用来增强API请求的首选加密算法。一起来看看它。

椭圆曲线 Elliptic curve

https://mathworld.wolfram.com/EllipticCurve.html
通俗地讲,椭圆曲线是一种三次曲线,其解被限制在拓扑等价于环面的空间区域中。Weierstrass椭圆函数 描述了如何从这个环面得到椭圆曲线的代数形式。叫椭圆曲线只是因为方程跟椭圆的曲线积分比较相似。y²=x³+ax+b (mod p) x,y∈Zp​

椭圆曲线密码学ECC

Elliptic Curves Cryptography,椭圆曲线密码学。是基于椭圆曲线数学的一种公钥加密方法。
假设我们都清楚非对称加密。在诸如 DES、AES 这类对称密码系统中,信息的发送方使用一把密钥进行加密,接收方使用相同的密钥进行解密。
而在公钥加密方法中,信息的加密和解密使用的密钥是不同的,称之为公钥 PublicKey私钥 PrivateKey(注:既可以公钥加密私钥解密,也可以私钥加密公钥解密),常用的公钥加密方法有:

两者的理论基础都是数论理论中的单向运算函数,这种函数有一个特点:正方向计算容易,反方向计算却十分困难。以RSA背后的因数大数分解理论为例:
373 × 751 = ?,如果有草稿纸很容易计算。那么如果是因数分解计算呢?比如,280123 = ? × ?要算出来挺困难的。这就是RSA的理论基础,两个质数(素数)的乘积很容易计算,但要将一个这样的乘积分解回去就困难了。ECC采用的与之类似,不同的是它采用的是离散对数问题(DLP,Discrete Logarithm Problem)制造单向计算的困难。

离散对数问题

在椭圆曲线中定义一个群。
1、群中的元素就是椭圆曲线上的点;
2、单位元就是无穷处的点0;
3、相反数P,是关于X轴对称的另一边的点;
4、二元运算规则定义如下:取一条直线上的三点(这条直线和椭圆曲线相交的三点),P, Q, R(皆非零),他们的总和等于0,
P+Q+R=0。

如果P, Q, R在一条直线上的话,他们满足: P+(Q+R)=Q+(P+R)=R+(P+Q)=⋯=0。
当P,Q点为同一点时,P=Q,满足:

这样,我们可以直观的证明:+运算符是符合交换律和结合律的,这是一个阿贝尔群。
因为阿贝尔群满足交换律和结合律,所以点P和点-R的二元运算结果必会在曲线上,即P+P+P的结果必会在曲线上的另一点Q,
以此类推,可以得出得出:

 Q=kP(k个相同的点P进行二元运算(数乘),记做kP)

ECC在有限域Fp定义公式:Q=kP,已知大数k和点P的情况下,很容易求点Q,但是已知的点P、点Q,却很难求得k,这就是经典的离散对数问题,ECC算法正是利用该特点进行加密,点Q为公钥,大数k为私钥,点P为基点,和RSA最大的实际区别,主要是密钥长度。

类比熟悉的实数域上,指数运算比对数运算容易得多。而这里d就是椭圆曲线密码系统中的私钥,B就是公钥,这也就是为什么可以用私钥推导出公钥,反之不行的原因。

密码学-04-离散对数问题与Diffie-Hellman密钥交换
区块链的基石--椭圆曲线密码学
椭圆曲线加密算法原理解析(ECC)
ECC加密算法入门介绍
您的SSL/TLS证书应该采用ECC加密算法了

加密原理

描述一条Fp上的椭圆曲线,常用到六个参量:T=(p,a,b,n,x,y)。
(p 、a 、b) 用来确定一条椭圆曲线,p为素数域内点的个数,a和b是其内的两个大数;
x,y为G基点的坐标,也是两个大数;
n为点G基点的阶;
以上六个量就可以描述一条椭圆曲线,有时候我们还会用到h(椭圆曲线上所有点的个数p与n相除的整数部分)。
现在我们描述一个利用椭圆曲线进行加密通信的过程:
1、选定一条椭圆曲线 Ep(a,b) 并取椭圆曲线上一点,作为基点P。
2、选择一个大数k作为私钥,并生成公钥 Q=kP。
3、将 Ep(a,b) 和点Q、P传给用户。
4、用户接到信息后 ,将待传输的明文编码到Ep(a,b)上的一点M,并产生一个随机整数r。
5、公钥加密(密文C是一个点对):C={rP, M+rQ}
6、私钥解密(M + rQ - k(rP) ,解密结果就是点M),公式:M + rQ - k(rP) = M + r(kP) - k(rP) = M
7、对点M进行解码就可以得到明文
假设在加密过程中,有一个第三者H,H只能知道椭圆曲线 Ep(a,b)、公钥Q、基点P、密文点C,而通过公钥Q、基点P求私钥k或者通过密文点C、基点P求随机数r都是非常困难的,因此得以保证数据传输的安全。

secp256k1

secp256k1是以太坊中使用的椭圆曲线,其参数可以点击维基:安全协议256k1查看,包括椭圆曲线的系数、生成元等。在高效密码学标准(Certicom Research,http://www.secg.org/sec2-v2.pdf)中进行了定义。

就是方程:y²=x³+7的一条曲线。

Secp256k1为基于Fp有限域上的椭圆曲线,由于其特殊构造的特殊性,其优化后的实现比其他曲线性能上可以特高30%,有明显以下两个优点:

ECC应用

因为在安全性、加解密性能、网络消耗方面有较大优势,ECC加密算法大有取代RSA成为下一代主流加密算法的趋势。如今ECC应用范围很广,在TLS、区块链(比特币、以太坊等等)、SM2国密算法、证书、银行政府机构等许多方面都有大量应用。

实际使用库

go https://godoc.org/github.com/decred/dcrd/dcrec/secp256k1
python https://pypi.org/project/secp256k1
java:https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on/1.65

阿里云盘 invalid X-Device-Id

因为阿里云盘API升级加固了,所以导致项目AliPan下载文件时出错,因为加固用的加密算法也是secp256k1,所以就研究研究。
解决办法就是了解加密过程,破解接口加密。具体参考大神:https://www.52pojie.cn/thread-1745677-1-1.html

具体步骤:

  1. 生成密钥对
  2. 对几个云盘属性拼接SHA256然后签名
  3. 用签出来的数据调用create_session接口
  4. 同一个session内就能调用下载了

pom.xml

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.49</version>
</dependency>
<dependency>
    <groupId>org.web3j</groupId>
    <artifactId>crypto</artifactId>
    <version>5.0.0</version>
</dependency>
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import org.bouncycastle.util.encoders.Hex;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Sign;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;


/**
 * @author RawChen
 * @date 2023-02-15
 */
public class Main47 {
    public static void main(String[] args) throws Exception {

        String appId = "5dde4e1bdf9e4966b387ba58f4b3fdc3";    //固定的
        String deviceId = "cd4xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        String userId = "78xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        String nonce = "0";

        BigInteger privateKeyInt = new BigInteger(256, new SecureRandom());
        BigInteger publicKeyInt = Sign.publicKeyFromPrivate(privateKeyInt);
        String privateKey = privateKeyInt.toString(16);
        String publicKey = publicKeyInt.toString(16);
        byte[] dataBytes = (appId + ":" + deviceId + ":" + userId + ":" + nonce).getBytes(StandardCharsets.UTF_8);
        byte[] dataHash = Hash.sha256(dataBytes);
        ECKeyPair keyPair = new ECKeyPair(new BigInteger(privateKey, 16), new BigInteger(publicKey, 16));
        Sign.SignatureData signatureInfo = Sign.signMessage(dataHash, keyPair, false);
        String signature = Hex.toHexString(signatureInfo.getR()) + Hex.toHexString(signatureInfo.getS()) + "01";
//        long expireTimeSec = System.currentTimeMillis() / 1000 + 300;

        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer xxxxxxxxxxxxxxxxxaccess_tokenxxxxxxxxxxxxxxxxxxxxxxx");
        headers.put("Content-Type", "application/json");
        headers.put("Referer", "https://www.aliyundrive.com");
        headers.put("x-canary", "client=web,app=adrive,version=v3.17.0");
        headers.put("x-device-id", deviceId);
        headers.put("x-signature", signature);


        // create session
        JSONObject param01 = new JSONObject();
        param01.put("deviceName", "测试设备名");
        param01.put("modelName", "测试型号");
        param01.put("nonce", "0");
        param01.put("pubKey", "04" + publicKey);

        String createSessionResult = HttpRequest.post("https://api.aliyundrive.com/users/v1/users/device/create_session")
                .addHeaders(headers)
                .body(param01.toJSONString())
                .execute()
                .body();
        System.out.println("create_session: " + createSessionResult);


        // down
        JSONObject param02 = new JSONObject();
        param02.put("all", false);
        param02.put("drive_id", "1030023");
        param02.put("file_id", "6318c8bc033bf24fa8b44ccb99e86dbxxxxxxxxxx");
        param02.put("expire_sec", 14400);

        String downResult = HttpRequest.post("https://api.aliyundrive.com/v2/file/get_download_url")
                .addHeaders(headers)
                .body(param02.toJSONString())
                .execute()
                .body();
        System.out.println("down:" + downResult);

    }
}

本文由 RawChen 发表, 最后编辑时间为:2023-02-20 23:24
如果你觉得我的文章不错,不妨鼓励我继续写作。

发表评论
选择表情
  1. 我的天太牛了 icon_twisted.png

       Windows 10   Chrome 111
Top