椭圆曲线数字签名算法(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 - 基于大因数分解
- ECC - 基于椭圆曲线和离散对数
两者的理论基础都是数论理论中的单向运算函数,这种函数有一个特点:正方向计算容易,反方向计算却十分困难。以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的乘积很容易dP = ?很容易 (Double-and-Add算法)
- 计算一个点由是由哪个数与生成元相乘得到的很困难 B = ?P
类比熟悉的实数域上,指数运算比对数运算容易得多。而这里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
具体步骤:
- 生成密钥对
- 对几个云盘属性拼接SHA256然后签名
- 用签出来的数据调用create_session接口
- 同一个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);
}
}
我的天太牛了