OpenSSL BIO_read 对字符串 returns 不完整的 base64 编码

OpenSSL BIO_read on string returns incomplete base64 encoding

我试图在将 RSA 密钥转换为 OpenSSL 中的十进制字符串后对其进行 Base64 编码。我能够对大部分字符串进行编码,除了最后几个字符,我真的不知道为什么。我知道有一个单行函数可以在 EVP 中执行此操作,但我已经在测试程序之外尝试过它,但我遇到了非常奇怪的内存错误。

我的代码:

char *rsa_string = BN_bn2dec(n);

printf("RSA modulus as BigNumber: %s\n", rsa_string);

BIO *base64_bio = BIO_new(BIO_f_base64());
BIO *rsa_bio = BIO_new(BIO_s_mem());

BIO_set_flags(base64_bio, BIO_FLAGS_BASE64_NO_NL);
BIO_push(base64_bio, rsa_bio);
int bytes_wrote = BIO_write(base64_bio, rsa_string, strlen(rsa_string));

int size = (((bytes_wrote / 3) * 4) + 1);
char *base64_encoded_key = malloc(size);
memset(base64_encoded_key, 0, size);

BIO_read(rsa_bio, base64_encoded_key, size);

printf("PEM base64 encoded key: %s\n", base64_encoded_key);

rsa_string的值:

24313072237482078080153238679657972370698125455764727604271323979485556075246432578166301643940422426917948305745382409095484476466658578953561552837314705043006862929591710426227781122807468842903611989398403414596798482701682344649614368612160626447765390887911656651474459060185299697662496646333059927160952849254412616907773180781994902777839713317482262499105976583975621942282154132092996199104128448823598401942504647814124310345584957610465014752297210548757190951415912761894769725791618353941501561569896413562323669731189309270885282683237856701825718378848399084628386291389996469470694254685203803176643

Base64编码:

MjQzMTMwNzIyMzc0ODIwNzgwODAxNTMyMzg2Nzk2NTc5NzIzNzA2OTgxMjU0NTU3NjQ3Mjc2MDQyNzEzMjM5Nzk0ODU1NTYwNzUyNDY0MzI1NzgxNjYzMDE2NDM5NDA0MjI0MjY5MTc5NDgzMDU3NDUzODI0MDkwOTU0ODQ0NzY0NjY2NTg1Nzg5NTM1NjE1NTI4MzczMTQ3MDUwNDMwMDY4NjI5Mjk1OTE3MTA0MjYyMjc3ODExMjI4MDc0Njg4NDI5MDM2MTE5ODkzOTg0MDM0MTQ1OTY3OTg0ODI3MDE2ODIzNDQ2NDk2MTQzNjg2MTIxNjA2MjY0NDc3NjUzOTA4ODc5MTE2NTY2NTE0NzQ0NTkwNjAxODUyOTk2OTc2NjI0OTY2NDYzMzMwNTk5MjcxNjA5NTI4NDkyNTQ0MTI2MTY5MDc3NzMxODA3ODE5OTQ5MDI3Nzc4Mzk3MTMzMTc0ODIyNjI0OTkxMDU5NzY1ODM5NzU2MjE5NDIyODIxNTQxMzIwOTI5OTYxOTkxMDQxMjg0NDg4MjM1OTg0MDE5NDI1MDQ2NDc4MTQxMjQzMTAzNDU1ODQ5NTc2MTA0NjUwMTQ3NTIyOTcyMTA1NDg3NTcxOTA5NTE0MTU5MTI3NjE4OTQ3Njk3MjU3OTE2MTgzNTM5NDE1MDE1NjE1Njk4OTY0MTM1NjIzMjM2Njk3MzExODkzMDkyNzA4ODUyODI2ODMyMzc4NTY3MDE4MjU3MTgzNzg4NDgzOTkwODQ2MjgzODYyOTEzODk5OTY0Njk0NzA2OTQyNTQ2ODUyMDM4MDMxNzY2

我将此输出与编码为 Base64 的其他程序进行比较,发现我的程序偏离了 4 个字符 (NDM=)。这是为什么?

我尝试过的:

根据我从示例中看到的内容,我所拥有的似乎是正确的。为什么 Base64 过滤器不生成整个字符串?

备注:

如有任何帮助或指导,我们将不胜感激。谢谢!

尽管要进行 base64 编码的数据源是这样的,但展示它是如何完成的一个非常基本的操作如下。

  • 生成 256 字节数据的随机块。
  • 打开一个Base64 BIO并配置它。
  • 打开基本内存生物
  • 链接上述两个bios。
  • 通过生物链写入数据
  • 刷新生物链。
  • 从内存生物中获取数据。
  • 关闭完整的 BIO 链。

差不多就这些了。现在代码:

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>

#include <openssl/bio.h>
#include <openssl/rand.h>
#include <openssl/randerr.h>

int main()
{
    // generate a random 256 byte block
    uint8_t hdata[256] = {0};
    RAND_bytes(hdata, sizeof hdata);
    hdata[0] &=0x7F; // don't ask.

    // display in stdout just to prove it's there
    BIO_dump_fp(stdout, hdata, sizeof hdata);

    // configure base64 filter
    BIO *b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

    // configure a memory bio
    BIO *bmem = BIO_new(BIO_s_mem());

    // chain bios
    BIO *bio = BIO_push(b64, bmem);

    // write to target chain and flush
    BIO_write(bio, hdata, sizeof hdata);
    BIO_flush(bio);

    // reap memory buffer
    char *ptr = NULL;
    long len = BIO_get_mem_data(bmem, &ptr);
    
    // dump the converted data to stdout
    fwrite(ptr, (size_t)len, 1, stdout);
    fputc('\n', stdout);
    fflush(stdout);

    // close BIO chain
    BIO_free_all(bio);

    return EXIT_SUCCESS;
}

示例输出(显然不同)

0000 - 5b 94 cd 8b 1c 45 b9 5a-8c 5d f1 e3 08 31 55 8f   [....E.Z.]...1U.
0010 - 8b 3c 29 7f 5d b1 72 82-12 6d 24 3f 04 6e 83 72   .<).].r..m$?.n.r
0020 - 1c 1d 01 5c 54 3b 2e c8-cc 47 5a 2f db ec 47 06   ...\T;...GZ/..G.
0030 - 95 25 13 f4 3b 92 2c c0-b6 88 41 d1 62 f7 f2 e4   .%..;.,...A.b...
0040 - 45 22 14 3a fc 1d a3 3b-b3 79 5b f0 c1 06 cb 56   E".:...;.y[....V
0050 - 87 f8 61 1e 82 9f 1b f0-fa 43 90 a0 12 18 28 40   ..a......C....(@
0060 - 88 32 ff f9 62 9f d6 eb-9c dc 69 fa 3a ca a5 ea   .2..b.....i.:...
0070 - 20 bb 62 9d 86 e4 76 8f-20 4f 19 42 a7 0d 15 c7    .b...v. O.B....
0080 - 83 78 79 20 b2 a3 44 64-bf 7f a0 84 11 a4 38 96   .xy ..Dd......8.
0090 - 17 83 18 96 84 6b df 94-e3 66 e2 88 63 58 d8 8f   .....k...f..cX..
00a0 - 49 67 b8 78 68 e2 8c 8b-55 cf 27 84 4c 35 91 80   Ig.xh...U.'.L5..
00b0 - 0c a0 63 2c f7 c0 c6 db-30 aa d9 8b 64 cb d2 8d   ..c,....0...d...
00c0 - c8 71 f9 0e 93 25 66 b4-c7 65 fc 85 a9 93 93 b7   .q...%f..e......
00d0 - 72 30 e9 72 e0 26 16 2c-a3 02 54 bd f6 d2 4a 8f   r0.r.&.,..T...J.
00e0 - 0b 9b 7a 6c 35 cd 2c 80-f8 50 0e 31 a9 0b 39 0c   ..zl5.,..P.1..9.
00f0 - b1 cf 67 b8 65 75 a3 98-ee 0b d5 6f a0 61 8b df   ..g.eu.....o.a..
W5TNixxFuVqMXfHjCDFVj4s8KX9dsXKCEm0kPwRug3IcHQFcVDsuyMxHWi/b7EcGlSUT9DuSLMC2iEHRYvfy5EUiFDr8HaM7s3lb8MEGy1aH+GEegp8b8PpDkKASGChAiDL/+WKf1uuc3Gn6Osql6iC7Yp2G5HaPIE8ZQqcNFceDeHkgsqNEZL9/oIQRpDiWF4MYloRr35TjZuKIY1jYj0lnuHho4oyLVc8nhEw1kYAMoGMs98DG2zCq2Ytky9KNyHH5DpMlZrTHZfyFqZOTt3Iw6XLgJhYsowJUvfbSSo8Lm3psNc0sgPhQDjGpCzkMsc9nuGV1o5juC9VvoGGL3w==

同花顺很重要。当您考虑 base64 流过滤器如何工作时,它将等待 3 个八位字节,然后再发出 4 个八位字节。它在内部可能会更加详尽,但凡人可能会这样写。因此,它不知道您何时“完成”写入数据,并以可能处于 partial/incomplete 三元组的状态结束,直到您这样说,然后您通过刷新 bio 链来完成。


您的文本字符串,Base64 编码

对您的文本字符串执行相同的操作与之前的代码非常相似。明明源数据不一样,其他都差不多

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/bio.h>
#include <openssl/evp.h>

int main()
{
    const char *str = 
    "2431307223748207808015323867965797237069812545576472760427132397948555"
    "6075246432578166301643940422426917948305745382409095484476466658578953"
    "5615528373147050430068629295917104262277811228074688429036119893984034"
    "1459679848270168234464961436861216062644776539088791165665147445906018"
    "5299697662496646333059927160952849254412616907773180781994902777839713"
    "3174822624991059765839756219422821541320929961991041284488235984019425"
    "0464781412431034558495761046501475229721054875719095141591276189476972"
    "5791618353941501561569896413562323669731189309270885282683237856701825"
    "718378848399084628386291389996469470694254685203803176643";

    const size_t slen = strlen(str);

    // display in stdout
    BIO_dump_fp(stdout, str, (int)slen);

    // configure base64 filter
    BIO *b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

    // configure a memory bio
    BIO *bmem = BIO_new(BIO_s_mem());

    // chain bios
    BIO *bio = BIO_push(b64, bmem);

    // write to target chain and flush
    BIO_write(bio, str, (int)slen);
    BIO_flush(bio);

    // reap memory buffer
    char *ptr = NULL;
    long len = BIO_get_mem_data(bmem, &ptr);
    
    // dump the converted data to stdout
    fwrite(ptr, (size_t)len, 1, stdout);
    fputc('\n', stdout);
    fflush(stdout);

    // close BIO chain
    BIO_free_all(bio);

    return EXIT_SUCCESS;
}

输出

0000 - 32 34 33 31 33 30 37 32-32 33 37 34 38 32 30 37   2431307223748207
0010 - 38 30 38 30 31 35 33 32-33 38 36 37 39 36 35 37   8080153238679657
0020 - 39 37 32 33 37 30 36 39-38 31 32 35 34 35 35 37   9723706981254557
0030 - 36 34 37 32 37 36 30 34-32 37 31 33 32 33 39 37   6472760427132397
0040 - 39 34 38 35 35 35 36 30-37 35 32 34 36 34 33 32   9485556075246432
0050 - 35 37 38 31 36 36 33 30-31 36 34 33 39 34 30 34   5781663016439404
0060 - 32 32 34 32 36 39 31 37-39 34 38 33 30 35 37 34   2242691794830574
0070 - 35 33 38 32 34 30 39 30-39 35 34 38 34 34 37 36   5382409095484476
0080 - 34 36 36 36 35 38 35 37-38 39 35 33 35 36 31 35   4666585789535615
0090 - 35 32 38 33 37 33 31 34-37 30 35 30 34 33 30 30   5283731470504300
00a0 - 36 38 36 32 39 32 39 35-39 31 37 31 30 34 32 36   6862929591710426
00b0 - 32 32 37 37 38 31 31 32-32 38 30 37 34 36 38 38   2277811228074688
00c0 - 34 32 39 30 33 36 31 31-39 38 39 33 39 38 34 30   4290361198939840
00d0 - 33 34 31 34 35 39 36 37-39 38 34 38 32 37 30 31   3414596798482701
00e0 - 36 38 32 33 34 34 36 34-39 36 31 34 33 36 38 36   6823446496143686
00f0 - 31 32 31 36 30 36 32 36-34 34 37 37 36 35 33 39   1216062644776539
0100 - 30 38 38 37 39 31 31 36-35 36 36 35 31 34 37 34   0887911656651474
0110 - 34 35 39 30 36 30 31 38-35 32 39 39 36 39 37 36   4590601852996976
0120 - 36 32 34 39 36 36 34 36-33 33 33 30 35 39 39 32   6249664633305992
0130 - 37 31 36 30 39 35 32 38-34 39 32 35 34 34 31 32   7160952849254412
0140 - 36 31 36 39 30 37 37 37-33 31 38 30 37 38 31 39   6169077731807819
0150 - 39 34 39 30 32 37 37 37-38 33 39 37 31 33 33 31   9490277783971331
0160 - 37 34 38 32 32 36 32 34-39 39 31 30 35 39 37 36   7482262499105976
0170 - 35 38 33 39 37 35 36 32-31 39 34 32 32 38 32 31   5839756219422821
0180 - 35 34 31 33 32 30 39 32-39 39 36 31 39 39 31 30   5413209299619910
0190 - 34 31 32 38 34 34 38 38-32 33 35 39 38 34 30 31   4128448823598401
01a0 - 39 34 32 35 30 34 36 34-37 38 31 34 31 32 34 33   9425046478141243
01b0 - 31 30 33 34 35 35 38 34-39 35 37 36 31 30 34 36   1034558495761046
01c0 - 35 30 31 34 37 35 32 32-39 37 32 31 30 35 34 38   5014752297210548
01d0 - 37 35 37 31 39 30 39 35-31 34 31 35 39 31 32 37   7571909514159127
01e0 - 36 31 38 39 34 37 36 39-37 32 35 37 39 31 36 31   6189476972579161
01f0 - 38 33 35 33 39 34 31 35-30 31 35 36 31 35 36 39   8353941501561569
0200 - 38 39 36 34 31 33 35 36-32 33 32 33 36 36 39 37   8964135623236697
0210 - 33 31 31 38 39 33 30 39-32 37 30 38 38 35 32 38   3118930927088528
0220 - 32 36 38 33 32 33 37 38-35 36 37 30 31 38 32 35   2683237856701825
0230 - 37 31 38 33 37 38 38 34-38 33 39 39 30 38 34 36   7183788483990846
0240 - 32 38 33 38 36 32 39 31-33 38 39 39 39 36 34 36   2838629138999646
0250 - 39 34 37 30 36 39 34 32-35 34 36 38 35 32 30 33   9470694254685203
0260 - 38 30 33 31 37 36 36 34-33                        803176643
MjQzMTMwNzIyMzc0ODIwNzgwODAxNTMyMzg2Nzk2NTc5NzIzNzA2OTgxMjU0NTU3NjQ3Mjc2MDQyNzEzMjM5Nzk0ODU1NTYwNzUyNDY0MzI1NzgxNjYzMDE2NDM5NDA0MjI0MjY5MTc5NDgzMDU3NDUzODI0MDkwOTU0ODQ0NzY0NjY2NTg1Nzg5NTM1NjE1NTI4MzczMTQ3MDUwNDMwMDY4NjI5Mjk1OTE3MTA0MjYyMjc3ODExMjI4MDc0Njg4NDI5MDM2MTE5ODkzOTg0MDM0MTQ1OTY3OTg0ODI3MDE2ODIzNDQ2NDk2MTQzNjg2MTIxNjA2MjY0NDc3NjUzOTA4ODc5MTE2NTY2NTE0NzQ0NTkwNjAxODUyOTk2OTc2NjI0OTY2NDYzMzMwNTk5MjcxNjA5NTI4NDkyNTQ0MTI2MTY5MDc3NzMxODA3ODE5OTQ5MDI3Nzc4Mzk3MTMzMTc0ODIyNjI0OTkxMDU5NzY1ODM5NzU2MjE5NDIyODIxNTQxMzIwOTI5OTYxOTkxMDQxMjg0NDg4MjM1OTg0MDE5NDI1MDQ2NDc4MTQxMjQzMTAzNDU1ODQ5NTc2MTA0NjUwMTQ3NTIyOTcyMTA1NDg3NTcxOTA5NTE0MTU5MTI3NjE4OTQ3Njk3MjU3OTE2MTgzNTM5NDE1MDE1NjE1Njk4OTY0MTM1NjIzMjM2Njk3MzExODkzMDkyNzA4ODUyODI2ODMyMzc4NTY3MDE4MjU3MTgzNzg4NDgzOTkwODQ2MjgzODYyOTEzODk5OTY0Njk0NzA2OTQyNTQ2ODUyMDM4MDMxNzY2NDM=

base64decode.org 处解码的 base64 行的副本将与您的源字符串完美对齐。


BIGNUM Base64 编码

关于 off-chance 我的怀疑是正确的,您的最终目标是 bignum 本身的 base64 编码,这也是可行的,几乎不需要更多的工作。使用原始源字符串,我们可以创建一个 BIGNUM,然后像以前一样通过 base64 过滤的生物链发送它:

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>

#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/evp.h>

int main()
{
    const char *str = 
    "2431307223748207808015323867965797237069812545576472760427132397948555"
    "6075246432578166301643940422426917948305745382409095484476466658578953"
    "5615528373147050430068629295917104262277811228074688429036119893984034"
    "1459679848270168234464961436861216062644776539088791165665147445906018"
    "5299697662496646333059927160952849254412616907773180781994902777839713"
    "3174822624991059765839756219422821541320929961991041284488235984019425"
    "0464781412431034558495761046501475229721054875719095141591276189476972"
    "5791618353941501561569896413562323669731189309270885282683237856701825"
    "718378848399084628386291389996469470694254685203803176643";

    // convert relaly big integer asci string to a bignum
    BIGNUM *bn = NULL;
    if (BN_asc2bn(&bn, str) == 1)
    {
        // convert the big number to big-endian binary.
        int nbytes = BN_num_bytes(bn);
        unsigned char *bin = OPENSSL_malloc(nbytes);
        BN_bn2bin(bn, bin);

        // dump to stdout
        BIO_dump_fp(stdout, bin, nbytes);

        // configure base64 filter
        BIO *b64 = BIO_new(BIO_f_base64());
        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

        // configure bio chain
        BIO *bmem = BIO_new(BIO_s_mem());
        BIO *bio = BIO_push(b64, bmem);
        BIO_write(bio, bin, nbytes);;
        BIO_flush(bio);

        // no longer need the BN or buffer
        OPENSSL_clear_free(bin, nbytes);
        BN_free(bn);

        // reap memory buffer
        char *ptr = NULL;
        long len = BIO_get_mem_data(bmem, &ptr);
        
        // dump the converted data to stdout
        fwrite(ptr, (size_t)len, 1, stdout);
        fputc('\n', stdout);
        fflush(stdout);

        // close BIO chain
        BIO_free_all(bio);
    }

    return EXIT_SUCCESS;
}

输出

0000 - c0 98 bc ce e0 43 b1 06-de 88 ff c2 f2 02 6d 08   .....C........m.
0010 - 92 99 30 4d 06 c4 e1 39-18 48 f8 24 bd a6 7e e0   ..0M...9.H.$..~.
0020 - 3d c3 7a 59 1d ff 70 a6-2e 8b 5d c9 c6 3d 38 cb   =.zY..p...]..=8.
0030 - aa f7 4a d6 1b 24 54 c4-9f 4f 74 b4 52 2b 9a 89   ..J..$T..Ot.R+..
0040 - 3b 72 d8 ce 60 fa dc 72-36 9d 0a 31 45 32 54 94   ;r..`..r6..1E2T.
0050 - 61 c4 9e 05 32 68 08 d8-d8 41 e3 0c d5 b3 81 13   a...2h...A......
0060 - ec 5c 95 c5 23 a7 71 a3-0d c0 e6 13 04 14 db 6c   .\..#.q........l
0070 - 9d f2 10 e0 52 ff 44 be-a9 c4 8a 8e ee 13 3f 4e   ....R.D.......?N
0080 - a1 3e 04 72 ea 35 5f 42-04 e7 aa b0 82 df c1 07   .>.r.5_B........
0090 - a6 db 7d d5 81 b7 33 cf-a9 bc 95 76 63 ae 9b 7a   ..}...3....vc..z
00a0 - f9 11 79 c0 31 8d e0 53-11 e6 34 3d a9 a6 53 9c   ..y.1..S..4=..S.
00b0 - 90 a6 68 da 0a 94 05 b3-0e 79 be a6 8b 82 4c 27   ..h......y....L'
00c0 - 76 3e 76 59 81 db dd dd-27 c4 ea cd b1 d9 b1 86   v>vY....'.......
00d0 - e3 7b f0 9a 7c d5 3c aa-ae a1 8d f0 96 73 2c 96   .{..|.<......s,.
00e0 - 53 01 4e 49 2e 4b ed 86-cd 98 60 99 8b 5a 21 c5   S.NI.K....`..Z!.
00f0 - 1a e6 b7 1d 45 8f d1 bf-83 f9 bc e6 46 14 7e c3   ....E.......F.~.
wJi8zuBDsQbeiP/C8gJtCJKZME0GxOE5GEj4JL2mfuA9w3pZHf9wpi6LXcnGPTjLqvdK1hskVMSfT3S0UiuaiTty2M5g+txyNp0KMUUyVJRhxJ4FMmgI2NhB4wzVs4ET7FyVxSOncaMNwOYTBBTbbJ3yEOBS/0S+qcSKju4TP06hPgRy6jVfQgTnqrCC38EHptt91YG3M8+pvJV2Y66bevkRecAxjeBTEeY0PammU5yQpmjaCpQFsw55vqaLgkwndj52WYHb3d0nxOrNsdmxhuN78Jp81TyqrqGN8JZzLJZTAU5JLkvths2YYJmLWiHFGua3HUWP0b+D+bzmRhR+ww==

上面显示控制台转储中的 256 个字节表示 big-endian 二进制形式的数字。这是经过 base64 编码并产生最后一行输出的数据。该代码看起来应该非常熟悉,因为它与本答案中的第一个示例基本相同;只是数据来源不同。

怀疑 这是你最终需要的,尽管你发布的代码表明你已经从一个 bignum 开始,所以上面代码的开头创建字符串中的 bignum 已经完成。