micro-ecc [适用于MCU的ECC算法库]
适用于 8 位、32 位和 64 位处理器的小型且快速的 ECDH 和 ECDSA 实现。
nano-ecc是micro-ecc的分支,两者相比,nano-ecc针对Arduino适配,但没有汇编级优化,而micro-ecc针对乘法在ARM处理器中的实现做了汇编级优化。配合M0/M4处理器,可以更快实施ECC算法:ECDH/ECDSA。
1
| https://github.com/kmackay/micro-ecc
|
1
| https://github.com/iSECPartners/nano-ecc
|
算法介绍
ECDSA是用于数字签名,是ECC与DSA的结合,整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC,最后签名出来的值也是分为r,s。而ECC(全称Elliptic Curves Cryptography)是一种椭圆曲线密码编码学。
ECDH每次用一个固定的DH key,导致不能向前保密(forward secrecy),所以一般都是用ECDHE(ephemeral)或其他版本的ECDH算法。ECDH则是基于ECC的DH( Diffie-Hellman)密钥交换算法。
ECC与RSA 相比,有以下的优点:
- 相同密钥长度下,安全性能更高,如160位ECC已经与1024位RSA、DSA有相同的安全强度。
- 计算量小,处理速度快,在私钥的处理速度上(解密和签名),ECC远 比RSA、DSA快得多。
- 存储空间占用小 ECC的密钥尺寸和系统参数与RSA、DSA相比要小得多, 所以占用的存储空间小得多。
- 带宽要求低使得ECC具有广泛得应用前景。
在 ECDHE 密钥交换中,服务端使用证书私钥对相关信息进行签名,如果浏览器能用证书公钥验证签名,就说明服务端确实拥有对应私钥,从而完成了服务端认证。密钥交换和服务端认证是完全分开的。
可用于 ECDHE 数字签名的算法主要有 RSA 和 ECDSA,也就是目前密钥交换 + 签名有三种主流选择:
- RSA 密钥交换(无需签名)
- ECDHE 密钥交换、RSA 签名
- ECDHE 密钥交换、ECDSA 签名;
移植说明
- 注意移植随机数生成器,在文件:
platform-specific.inc
- 移植时注意平台定义,该库基于各个平台都做了一些优化,默认会自动选择平台,在
uECC.h
文件下定义 #define uECC_PLATFORM uECC_arch_other
, 其中 uECC_arch_other 根据平台自己去适配
测试代码
注意测试代码需要使用 sha256
算法, 请参考其他 sha256
算法章节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| #include <stdio.h>
#include "uECC.h" #include "sha256.h"
void out_hex_string(char *info, uint8_t *buf, uint32_t size) { printf("%s : \r\n", info); for (int i = 0; i < size; i++) { printf("%02x ", buf[i]); } printf("\r\n"); }
#define ECDSA256_BYTES (32) #define ECDSA256_PRIVATE_KEY_SIZE (ECDSA256_BYTES) #define ECDSA256_PUBLIC_KEY_SIZE (ECDSA256_BYTES * 2) #define ECDSA256_SIGNATURE_SIZE (ECDSA256_BYTES * 2)
int main(int argc, char **argv) { int ret; int i, c; int num_curves = 0;
uint8_t public_key[ECDSA256_PUBLIC_KEY_SIZE]; uint8_t private_key[ECDSA256_PRIVATE_KEY_SIZE];
char use_data[10] = "test"; uint8_t sha256[SHA256_DIGEST_SIZE]; uint8_t signature[ECDSA256_SIGNATURE_SIZE];
const struct uECC_Curve_t * curves[5];
#if uECC_SUPPORTS_secp160r1 curves[num_curves++] = uECC_secp160r1(); #endif #if uECC_SUPPORTS_secp192r1 curves[num_curves++] = uECC_secp192r1(); #endif #if uECC_SUPPORTS_secp224r1 curves[num_curves++] = uECC_secp224r1(); #endif #if uECC_SUPPORTS_secp256r1 curves[num_curves++] = uECC_secp256r1(); #endif #if uECC_SUPPORTS_secp256k1 curves[num_curves++] = uECC_secp256k1(); #endif
sha256_hash(use_data, strlen(use_data), sha256); out_hex_string("sha256", sha256, sizeof(sha256));
uint32_t test_cnt = 0;
for (c = 0; c < num_curves; ++c) { { printf("."); fflush(stdout);
if (!uECC_make_key(public_key, private_key, curves[c])) { printf("uECC_make_key() failed\n"); return 1; } out_hex_string("private_key", private_key, uECC_curve_private_key_size(curves[c])); out_hex_string("public_key", public_key, uECC_curve_public_key_size(curves[c])); if (!uECC_sign(private_key, sha256, sizeof(sha256), signature, curves[c])) { printf("uECC_sign() failed\n"); return 1; } out_hex_string("signature", signature, ECDSA256_SIGNATURE_SIZE);
if (!uECC_verify(public_key, sha256, sizeof(sha256), signature, curves[c])) { printf("uECC_verify() failed\n"); return 1; } printf("uECC %d, test OK", c);
test_cnt++; } printf("\n"); } return 0; }
|