【问题标题】:c programming - working with BIGNUM in opensslc 编程 - 在 openssl 中使用 BIGNUM
【发布时间】:2022-01-20 16:29:28
【问题描述】:

我正在尝试使用 c 中的 openssl 库添加两个大数,但我真的不知道如何使用它。

openssl - BN_add() 的文档在这里https://www.openssl.org/docs/man3.0/man3/BN_add.html

//#include <openssl/bn.h>

//BN_add() adds a and b and places the result in r (r=a+b).
//r may be the same BIGNUM as a or b.

int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);

a & b 对我有什么期望?一个字节数组?一个字符串?

谁曾在 openssl 中添加过大数并有一个简单的例子?

【问题讨论】:

  • 你有什么问题?
  • 了解了吗? a& b 对我有什么期望? char 的数组?一个字符串?
  • 两个 BIGNUM 数字要相加吗?因为如果是这样,API 是直截了当的。如果没有,也许获得这些将是首先研究的事情。
  • 正是肖恩所说的。我怀疑BN_dec2bn 将派上用场,将您的数字字符串定位到BIGNUM 对象中。这就是为什么我说不要本末倒置。如果您想使用BN_add,您需要三个BIGNUM 对象,其中两个填充有您要添加的数字。因此,首先应该关注那些使用 OpenSSL BN 库中大量 API 的人。
  • 我认为在您的情况下,BN_dec2bn 将正确地将您的数字字符串转换为自分配的 BIGNUM;您仍然需要稍后释放它,但如果您从转换中获得它们,则不需要BN_new。由你决定。

标签: c pointers openssl bigdata pointer-arithmetic


【解决方案1】:

要使用BN_add,您需要三个BIGNUM 工件:您尝试添加的两个操作数和一个存储结果的位置。操作数的来源可能会有所不同,这取决于源数据的性质和其中可能的转换。应使用BN_new 获取结果。

下面是一个使用两个十进制数字字符串的简单示例:

#include <stdio.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>

int main()
{
    const char n1[] = "12345678912345789123456789123456789";
    const char n2[] = "12345678912345789123456789123456789";

    BIGNUM *bn1 = NULL;
    BN_dec2bn(&bn1, n1);

    BIGNUM *bn2 = NULL;
    BN_dec2bn(&bn2, n2);

    BIGNUM *bn3 = BN_new();
    BN_add(bn3, bn1, bn2);

    char *n3 = BN_bn2dec(bn3);
    printf("%s\n%s\n%s\n", n1, n2, n3);
    OPENSSL_free(n3); // don't forget to free this.
    
    BN_free(bn1);
    BN_free(bn2);
    BN_free(bn3);

    return 0;
}

输出

12345678912345789123456789123456789
12345678912345789123456789123456789
24691357824691578246913578246913578

请注意,我们确保释放我们获取的所有内容,包括转换为十进制字符字符串的结果,根据BN_bn2dec 文档,必须使用OPENSSL_free 释放。


这不是唯一的方法,不同的方法高度依赖于源数据。例如,我们可以修改上面的程序,将两个 256 位数字从 big-endian 字节八位字节转换为BIGNUM。为此,我们可以使用BN_bin2bn。然而,其余代码看起来相似(除了一些必须释放的额外转换缓冲区)。

#include <stdio.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>

int main()
{
    unsigned char n1[32];
    unsigned char n2[32];

    RAND_bytes(n1, sizeof n1);
    RAND_bytes(n2, sizeof n2);

    BIGNUM *bn1 = BN_bin2bn(n1, sizeof n1, NULL);
    BIGNUM *bn2 = BN_bin2bn(n2, sizeof n2, NULL);

    BIGNUM *bn3 = BN_new();
    BN_add(bn3, bn1, bn2);

    char *s1 = BN_bn2dec(bn1);
    char *s2 = BN_bn2dec(bn2);
    char *s3 = BN_bn2dec(bn3);
    printf("%s\n%s\n%s\n", s1, s2, s3);
    OPENSSL_free(s1);
    OPENSSL_free(s2);
    OPENSSL_free(s3);
    
    BN_free(bn1);
    BN_free(bn2);
    BN_free(bn3);

    return 0;
}

输出(显然不同)

12848991999079618356122471791635779303297173135339588614513279277444395635360
47516096440756489210553139954635811049213722081352926332729551875133172387567
60365088439836107566675611746271590352510895216692514947242831152577568022927

最后,一些操作利用上下文来执行操作。对于我们在这里执行的单次操作,它不会特别有益,但是大量的密码算法代码对大数执行许多复杂的操作。提供临时存储上下文来管理大量内存分配和释放是上下文的主要用途。

您将在下面看到一个示例,该示例生成两个 128 位数字作为随机 blob,然后将它们相乘以产生所需的结果。

#include <stdio.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>

int main()
{
    unsigned char n1[16];
    unsigned char n2[16];

    RAND_bytes(n1, sizeof n1);
    RAND_bytes(n2, sizeof n2);

    BIGNUM *bn1 = BN_bin2bn(n1, sizeof n1, NULL);
    BIGNUM *bn2 = BN_bin2bn(n2, sizeof n2, NULL);
    BIGNUM *bn3 = BN_new();

    // create context
    BN_CTX *ctx = BN_CTX_new();
    BN_mul(bn3, bn1, bn2, ctx);
    BN_CTX_free(ctx);

    char *s1 = BN_bn2dec(bn1);
    char *s2 = BN_bn2dec(bn2);
    char *s3 = BN_bn2dec(bn3);
    printf("%s\n%s\n%s\n", s1, s2, s3);
    OPENSSL_free(s1);
    OPENSSL_free(s2);
    OPENSSL_free(s3);
    
    BN_free(bn1);
    BN_free(bn2);
    BN_free(bn3);

    return 0;
}

输出(显然不同)

132784775043065614238831600062417274250
106732277254089889576391506780872414280
14172421425018434896232647200508450669828492339359021022467696136374376290000

有多种web sites,如果您有任何疑问,可以在其中验证上述产品是否准确;我意识到,与我们之前进行的简单加法运算相比,长期处理要麻烦得多。

【讨论】:

  • 完美解释,不知道要保存一些额外的转换缓冲区,必须释放它,谢谢
  • 一些大数字操作会变得更加复杂,其中必须使用 context。当/如果您需要此类操作时,他们的 BN_xxxx api 系列上的 OpenSSL 文档非常好(相信我;它已经走过了漫长的道路;它曾经非常糟糕)。然而,即使在那种情况下,object 管理(获取、使用和释放BIGNUM 实例)的基本前提基本相同。如果你能掌握上面的代码,那么转向需要上下文的更复杂的操作会更容易接受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
  • 2013-11-27
相关资源
最近更新 更多