铜锁密码库

BabaSSL

介绍

BabaSSL是一款轻巧、灵活且靠谱的密码学和TLS协议工具集。BabaSSL是蚂蚁集团和阿里集团的各主要业务中所使用的底层密码库,现在开源出来供业界使用。BabaSSL广泛的应用在包括网络、存储、移动端App等场景中。

BabaSSL 是 OpenSSL 的衍生版,内部支持了很多椭圆曲线算法的实现。

网站:https://www.babassl.cn/

github:https://github.com/Tongsuo-Project/Tongsuo

文档:https://babassl.readthedocs.io/zh/latest/
https://www.yuque.com/tsdoc

实现功能:

  • 密码学算法
    • 中国商用密码算法:SM2、SM3、SM4、祖冲之等
    • 国际主流算法:ECDSA、RSA、AES、SHA等
    • 同态加密算法:EC-ElGamal、Paillier*等
    • 后量子密码学*:LAC、NTRU、Saber、Dilithium等
  • 安全通信协议
    • 支持GB/T 38636-2020 TLCP标准,即双证书国密通信协议
    • 支持RFC 8998,即TLS 1.3 + 国密单证书
    • 支持QUIC API
    • 支持Delegated Credentials功能,基于draft-ietf-tls-subcerts-10
    • 支持TLS证书压缩
    • 支持紧凑TLS协议*

安装

参考:https://tongsuo.readthedocs.io/zh/latest/Tutorial/PHE/ec-elgamal-sample/

  • 下载
git clone git@github.com:Tongsuo-Project/Tongsuo.git
  • 编译

最新参考:https://www.yuque.com/tsdoc/ts/rp7ul8a4ttav8ql9

# 编译参数需要加上:enable-ec_elgamal,我这里是在 macOS 系统上编译,所以是 darwin64-x86_64-cc,其他系统需要切换一下
./Configure darwin64-x86_64-cc --debug no-shared no-threads enable-ec_elgamal --strict-warnings -fPIC --prefix=/usr/local/tongsuo-debug

# 编译
make -j4

# 安装到目录 /usr/local/tongsuo-debug
sudo make install

测试

ec_elgamal

//ec_elgamal_test.c
#include <stdio.h>
#include <time.h>
#include <openssl/ec.h>
#include <openssl/pem.h>

#define CLOCKS_PER_MSEC (CLOCKS_PER_SEC/1000)

int main(int argc, char *argv[])
{
    int ret = -1;
    uint32_t r;
    //密钥生成
    clock_t begin, end;
    EC_KEY *sk_eckey = NULL, *pk_eckey = NULL;
    EC_ELGAMAL_CTX *ctx1 = NULL, *ctx2 = NULL;
    EC_ELGAMAL_CIPHERTEXT *c1 = NULL, *c2 = NULL, *c3 = NULL;
    EC_ELGAMAL_DECRYPT_TABLE *table = NULL;
    FILE *pk_file = fopen("ec-pk.pem", "rb");
    FILE *sk_file = fopen("ec-sk.pem", "rb");
    if ((pk_eckey = PEM_read_EC_PUBKEY(pk_file, NULL, NULL, NULL)) == NULL)
        goto err;
    if ((sk_eckey = PEM_read_ECPrivateKey(sk_file, NULL, NULL, NULL)) == NULL)
        goto err;

    if ((ctx1 = EC_ELGAMAL_CTX_new(pk_eckey)) == NULL)
        goto err;
    if ((ctx2 = EC_ELGAMAL_CTX_new(sk_eckey)) == NULL)
        goto err;

    //创建解密表
    begin = clock();
    if ((table = EC_ELGAMAL_DECRYPT_TABLE_new(ctx2, 0)) == NULL)
        goto err;

    EC_ELGAMAL_CTX_set_decrypt_table(ctx2, table);
    end = clock();
    printf("EC_ELGAMAL_DECRYPT_TABLE_new(1) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);

    if ((c1 = EC_ELGAMAL_CIPHERTEXT_new(ctx1)) == NULL)
        goto err;
    if ((c2 = EC_ELGAMAL_CIPHERTEXT_new(ctx1)) == NULL)
        goto err;

    //加密20000021
    begin = clock();
    if (!EC_ELGAMAL_encrypt(ctx1, c1, 20000021))
        goto err;
    end = clock();
    printf("EC_ELGAMAL_encrypt(20000021) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);

    //加密500
    begin = clock();
    if (!EC_ELGAMAL_encrypt(ctx1, c2, 500))
        goto err;
    end = clock();
    printf("EC_ELGAMAL_encrypt(500) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);

    if ((c3 = EC_ELGAMAL_CIPHERTEXT_new(ctx1)) == NULL)
        goto err;

    //密文相加:20000021+500
    begin = clock();
    if (!EC_ELGAMAL_add(ctx1, c3, c1, c2))
        goto err;
    end = clock();
    printf("EC_ELGAMAL_add(C2000021,C500) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);

    //解密:20000021+500
    begin = clock();
    if (!(EC_ELGAMAL_decrypt(ctx2, &r, c3)))
        goto err;
    end = clock();
    printf("EC_ELGAMAL_decrypt(C20000021,C500) result: %d, cost: %lfms\n", r, (double)(end - begin)/CLOCKS_PER_MSEC);

    //标量乘:500*800
    begin = clock();
    if (!EC_ELGAMAL_mul(ctx1, c3, c2, 800))
        goto err;
    end = clock();
    printf("EC_ELGAMAL_mul(C500,800) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);

    //解密:500*800
    begin = clock();
    if (!(EC_ELGAMAL_decrypt(ctx2, &r, c3)))
        goto err;
    end = clock();
    printf("EC_ELGAMAL_decrypt(C500,800) result: %d, cost: %lfms\n", r, (double)(end - begin)/CLOCKS_PER_MSEC);

    //将密文500*800编码为二进制文件
    printf("EC_ELGAMAL_CIPHERTEXT_encode size: %zu\n", EC_ELGAMAL_CIPHERTEXT_encode(ctx2, NULL, 0, NULL, 1));

    ret = 0;
    err:
    EC_KEY_free(sk_eckey);
    EC_KEY_free(pk_eckey);
    EC_ELGAMAL_DECRYPT_TABLE_free(table);
    EC_ELGAMAL_CIPHERTEXT_free(c1);
    EC_ELGAMAL_CIPHERTEXT_free(c2);
    EC_ELGAMAL_CIPHERTEXT_free(c3);
    EC_ELGAMAL_CTX_free(ctx1);
    EC_ELGAMAL_CTX_free(ctx2);
    fclose(sk_file);
    fclose(pk_file);
    return ret;
}
  • 编译demo
gcc -Wall -g -o ec_elgamal_test ./ec_elgamal_test.c -I/usr/local/tongsuo-debug/include -L/usr/local/tongsuo-debug/lib -lssl -lcrypto
  • 生成公私钥
# 先生成私钥,这里生成的是 SM2 曲线的私钥
/usr/local/tongsuo-debug/bin/openssl ecparam -genkey -name SM2 -out ec-sk.pem
# 用私钥生成公钥
/usr/local/tongsuo-debug/bin/openssl ec -in ./ec-sk.pem -pubout -out ec-pk.pem
  • 运行
./ec_elgamal_test
EC_ELGAMAL_DECRYPT_TABLE_new(1) cost: 2410.917000ms
EC_ELGAMAL_encrypt(20000021) cost: 1.605000ms
EC_ELGAMAL_encrypt(500) cost: 1.547000ms
EC_ELGAMAL_add(C2000021,C500) cost: 0.019000ms
EC_ELGAMAL_decrypt(C20000021,C500) result: 20000521, cost: 12.281000ms
EC_ELGAMAL_mul(C500,800) cost: 2.257000ms
EC_ELGAMAL_decrypt(C500,800) result: 400000, cost: 1.216000ms
EC_ELGAMAL_CIPHERTEXT_encode size: 66
  • 注意

EC_ELGAMAL_DECRYPT_TABLE_new 函数第二个参数(0不支持,1支持)指定是否支持负数解密(为 1 时表示该解密表可以解密负数,初始化解密表时将可能的负数运算后插入到 hash 中),如果支持负数解密会影响解密性能,因为查询解密表的次数变多了,以及点的运算变多了,同时构造支持负数的解密表需要的时间也比较长。如下是支持负数解密的运行结果:

EC_ELGAMAL_DECRYPT_TABLE_new(1) cost: 114581.404000ms
EC_ELGAMAL_encrypt(20000021) cost: 1.806000ms
EC_ELGAMAL_encrypt(500) cost: 1.783000ms
EC_ELGAMAL_add(C2000021,C500) cost: 0.011000ms
EC_ELGAMAL_decrypt(C20000021,C500) result: 20000521, cost: 532.148000ms
EC_ELGAMAL_mul(C500,800) cost: 1.759000ms
EC_ELGAMAL_decrypt(C500,800) result: 400000, cost: 292.958000ms
EC_ELGAMAL_CIPHERTEXT_encode size: 66

paillier

//paillier_test.c
#include <stdio.h>
#include <time.h>
#include <openssl/paillier.h>
#include <openssl/pem.h>

#define CLOCKS_PER_MSEC (CLOCKS_PER_SEC/1000)

int main(int argc, char *argv[])
{
    int ret = -1;
    int32_t r;
    clock_t begin, end;
    PAILLIER_KEY *pail_key = NULL, *pail_pub = NULL;
    PAILLIER_CTX *ctx1 = NULL, *ctx2 = NULL;
    PAILLIER_CIPHERTEXT *c1 = NULL, *c2 = NULL, *c3 = NULL;
    FILE *pk_file = fopen("pail-pub.pem", "rb");
    FILE *sk_file = fopen("pail-key.pem", "rb");

    if ((pail_pub = PEM_read_PAILLIER_PublicKey(pk_file, NULL, NULL, NULL)) == NULL)
        goto err;
    if ((pail_key = PEM_read_PAILLIER_PrivateKey(sk_file, NULL, NULL, NULL)) == NULL)
        goto err;

    if ((ctx1 = PAILLIER_CTX_new(pail_pub, PAILLIER_MAX_THRESHOLD)) == NULL)
        goto err;
    if ((ctx2 = PAILLIER_CTX_new(pail_key, PAILLIER_MAX_THRESHOLD)) == NULL)
        goto err;

    if ((c1 = PAILLIER_CIPHERTEXT_new(ctx1)) == NULL)
        goto err;
    if ((c2 = PAILLIER_CIPHERTEXT_new(ctx1)) == NULL)
        goto err;
    if ((c3 = PAILLIER_CIPHERTEXT_new(ctx1)) == NULL)
        goto err;

    printf("\n\n--------- 加密1024 ---------\n\n");
    begin = clock();
    if (!PAILLIER_encrypt(ctx1, c1, 1024))
        goto err;
    end = clock();
    printf("PAILLIER_encrypt(1024) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);
    begin = clock();
    if (!(PAILLIER_decrypt(ctx2, &r, c1)))
        goto err;
    end = clock();
    printf("PAILLIER_decrypt(C1024) result: %d, cost: %lfms\n", r, (double)(end - begin)/CLOCKS_PER_MSEC);

    printf("\n\n--------- c2c:1024+1024 ---------\n\n");
    begin = clock();
    if (!PAILLIER_add(ctx1, c2, c1, c1))
        goto err;
    end = clock();
    printf("PAILLIER_add(C1024,C1024) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);
    begin = clock();
    if (!(PAILLIER_decrypt(ctx2, &r, c2)))
        goto err;
    end = clock();
    printf("PAILLIER_decrypt(C1024,C1024) result: %d, cost: %lfms\n", r, (double)(end - begin)/CLOCKS_PER_MSEC);

    printf("\n\n--------- c2m:1024+1024 ---------\n\n");
    begin = clock();
    if (!PAILLIER_add_plain(ctx1, c3, c1, 1024))
        goto err;
    end = clock();
    printf("PAILLIER_add(C1024,m1024) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);
    begin = clock();
    if (!(PAILLIER_decrypt(ctx2, &r, c3)))
        goto err;
    end = clock();
    printf("PAILLIER_decrypt(C1024,m1024) result: %d, cost: %lfms\n", r, (double)(end - begin)/CLOCKS_PER_MSEC);

    printf("\n\n--------- c*m:1024*800 ---------\n\n");
    begin = clock();
    if (!PAILLIER_mul(ctx1, c3, c1, 800))
        goto err;
    end = clock();
    printf("PAILLIER_mul(C1024,m800) cost: %lfms\n", (double)(end - begin)/CLOCKS_PER_MSEC);
    begin = clock();
    if (!(PAILLIER_decrypt(ctx2, &r, c3)))
        goto err;
    end = clock();
    printf("PAILLIER_decrypt(C1024,m800) result: %d, cost: %lfms\n", r, (double)(end - begin)/CLOCKS_PER_MSEC);
    
    ret = 0;
err:
    PAILLIER_KEY_free(pail_key);
    PAILLIER_KEY_free(pail_pub);
    PAILLIER_CIPHERTEXT_free(c1);
    PAILLIER_CIPHERTEXT_free(c2);
    PAILLIER_CIPHERTEXT_free(c3);
    PAILLIER_CTX_free(ctx1);
    PAILLIER_CTX_free(ctx2);
    fclose(sk_file);
    fclose(pk_file);
    return ret;
}

/*
运行:gcc -Wall -g -o paillier_test ./paillier_test.c -I/opt/tongsuo/include -L/opt/tongsuo/lib -lssl -lcrypto
*/
  • 编译
gcc -Wall -g -o paillier_test ./paillier_test.c -I/opt/tongsuo/include -L/opt/tongsuo/lib -lssl -lcrypto
  • 密钥生成
# 先生成私钥(以下命令生成私钥,保存在pail-key.pem)
/opt/tongsuo/bin/openssl paillier -keygen 10
# 用私钥生成公钥
/opt/tongsuo/bin/openssl paillier -pubgen -key_in ./pail-key.pem -out pail-pub.pem
  • 执行
./paillier_test

image

posted @ 2022-08-10 15:13  PamShao  阅读(1643)  评论(0编辑  收藏  举报