RSA与DH算法
RSA
RSA可以用于加密和签名,用公钥和私钥可以对文件做验证。
但RSA无法解决前向加密的问题,如果RSA的私钥泄漏,之前的消息均可用私钥解密出来。
RSA可以做密钥传输,B使用A的密钥对中的公钥加密数据,只有B用它的私钥才能解开。但RSA的公钥也不能在公网中传递,依然会有被中间人攻击的可能。
DH
DH的使用双方均有一对密钥,如果一方的公钥和私钥泄漏,依然无法破解之前的数据。
DH算法本身不包含身份认证机制,如果AB在交换公钥时被截获,C插入一对DH密钥,分别与AB通信,则可以截取信息。
Curve25519椭圆曲线算法
Curve25519是一种高水平的DH函数,提供128位的安全心,是最快的ECC曲线。
使用一个32字节的私钥,再根据私钥计算出32字节公钥。
B用户的公钥+A用户的私钥、A用户的公钥+B用户的私钥可以计算出一个32字节的共享密钥提供给两个用户使用,做AES加密。
Ed25519加密解密很快,生成时间短而且安全性更高,rsa则加密解密稍慢,生成时间长,安全性没有ed25519高,只是rsa基本都是默认,所以用的人更多,但是建议转换为ed25519,网站软件现在基本都支持了.
验签逻辑
curve25519_sign
- 将 Curve25519的私钥 转换为 Ed25519的公钥
- 使用 Curve25519的私钥 和 Ed25519的公钥 对数据进行签名。
- 返回加密结果
curve25519_verify
参数:加密数据,Curve25519公钥,原始数据
- 将 Cureve25519的公钥 转换成 Ed25519的公钥 。
- 使用 Ed25519的公钥 计算出 签名数据,将签名数据从加密数据中提取出来。
- 再将原始数据与签名数据拼接生成 验证体数据A 。
- 使用 Ed25519的公钥 ,验证体数据A,原始数据,生成 验证体数据B。
- 验证解密结果是否成功
void curve25519_keygen(unsigned char* curve25519_pubkey_out,
const unsigned char* curve25519_privkey_in)
{
ge_p3 ed; /* Ed25519 pubkey point */
fe ed_y, ed_y_plus_one, one_minus_ed_y, inv_one_minus_ed_y;
fe mont_x;
/* Perform a fixed-base multiplication of the Edwards base point,
(which is efficient due to precalculated tables), then convert
to the Curve25519 montgomery-format public key. In particular,
convert Curve25519's "montgomery" x-coordinate into an Ed25519
"edwards" y-coordinate:
mont_x = (ed_y + 1) / (1 - ed_y)
with projective coordinates:
mont_x = (ed_y + ed_z) / (ed_z - ed_y)
NOTE: ed_y=1 is converted to mont_x=0 since fe_invert is mod-exp
*/
ge_scalarmult_base(&ed, curve25519_privkey_in);
fe_add(ed_y_plus_one, ed.Y, ed.Z);
fe_sub(one_minus_ed_y, ed.Z, ed.Y);
fe_invert(inv_one_minus_ed_y, one_minus_ed_y);
fe_mul(mont_x, ed_y_plus_one, inv_one_minus_ed_y);
fe_tobytes(curve25519_pubkey_out, mont_x);
}
int curve25519_sign(unsigned char* signature_out,
const unsigned char* curve25519_privkey,
const unsigned char* msg, const unsigned long msg_len,
const unsigned char* random)
{
ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */
unsigned char ed_pubkey[32]; /* Ed25519 encoded pubkey */
unsigned char *sigbuf; /* working buffer */
unsigned char sign_bit = 0;
if ((sigbuf = malloc(msg_len + 128)) == 0) {
memset(signature_out, 0, 64);
return -1;
}
/* Convert the Curve25519 privkey to an Ed25519 public key */
ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey);
ge_p3_tobytes(ed_pubkey, &ed_pubkey_point);
sign_bit = ed_pubkey[31] & 0x80;
/* Perform an Ed25519 signature with explicit private key */
crypto_sign_modified(sigbuf, msg, msg_len, curve25519_privkey,
ed_pubkey, random);
memmove(signature_out, sigbuf, 64);
/* Encode the sign bit into signature (in unused high bit of S) */
signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */
signature_out[63] |= sign_bit;
free(sigbuf);
return 0;
}
int curve25519_verify(const unsigned char* signature,
const unsigned char* curve25519_pubkey,
const unsigned char* msg, const unsigned long msg_len)
{
fe mont_x, mont_x_minus_one, mont_x_plus_one, inv_mont_x_plus_one;
fe one;
fe ed_y;
unsigned char ed_pubkey[32];
unsigned long long some_retval;
unsigned char *verifybuf = NULL; /* working buffer */
unsigned char *verifybuf2 = NULL; /* working buffer #2 */
int result;
if ((verifybuf = malloc(msg_len + 64)) == 0) {
result = -1;
goto err;
}
if ((verifybuf2 = malloc(msg_len + 64)) == 0) {
result = -1;
goto err;
}
/* Convert the Curve25519 public key into an Ed25519 public key. In
particular, convert Curve25519's "montgomery" x-coordinate into an
Ed25519 "edwards" y-coordinate:
ed_y = (mont_x - 1) / (mont_x + 1)
NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp
Then move the sign bit into the pubkey from the signature.
*/
fe_frombytes(mont_x, curve25519_pubkey);
fe_1(one);
fe_sub(mont_x_minus_one, mont_x, one);
fe_add(mont_x_plus_one, mont_x, one);
fe_invert(inv_mont_x_plus_one, mont_x_plus_one);
fe_mul(ed_y, mont_x_minus_one, inv_mont_x_plus_one);
fe_tobytes(ed_pubkey, ed_y);
/* Copy the sign bit, and remove it from signature */
ed_pubkey[31] &= 0x7F; /* bit should be zero already, but just in case */
ed_pubkey[31] |= (signature[63] & 0x80);
memmove(verifybuf, signature, 64);
verifybuf[63] &= 0x7F;
memmove(verifybuf+64, msg, msg_len);
/* Then perform a normal Ed25519 verification, return 0 on success */
/* The below call has a strange API: */
/* verifybuf = R || S || message */
/* verifybuf2 = internal to next call gets a copy of verifybuf, S gets
replaced with pubkey for hashing, then the whole thing gets zeroized
(if bad sig), or contains a copy of msg (good sig) */
result = crypto_sign_open(verifybuf2, &some_retval, verifybuf, 64 + msg_len, ed_pubkey);
err:
if (verifybuf != NULL) {
free(verifybuf);
}
if (verifybuf2 != NULL) {
free(verifybuf2);
}
return result;
}