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=)。这是为什么?
我尝试过的:
- OpenSSL 的 BIO 文档 - https://www.openssl.org/docs/manmaster/man3/BIO_f_base64.html
- OpenSSL 的源代码 - https://github.com/openssl/openssl/blob/d9f073575fdb07b486cd1b38974cd177687ccc1e/apps/rand.c
- BIO 操作中 BIO 的不同排序,这是唯一产生 Base64 输出的配置。
- 为 Base64 BIO 读取输出缓冲区提供比所需更多的内存(以防大小计算错误)。
- 我尝试调用 read() 两次,但第二次调用 returns -1,这显然意味着 BIO 认为没有什么可读的了。
根据我从示例中看到的内容,我所拥有的似乎是正确的。为什么 Base64 过滤器不生成整个字符串?
备注:
这只是一个测试程序,用于了解如何使用 API,因此我不会刷新 BIO。
在我添加BIO_set_flags(base64_bio, BIO_FLAGS_BASE64_NO_NL)
代码之前,编码错了40个字符...我也不明白。
如有任何帮助或指导,我们将不胜感激。谢谢!
尽管要进行 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 已经完成。
我试图在将 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=)。这是为什么?
我尝试过的:
- OpenSSL 的 BIO 文档 - https://www.openssl.org/docs/manmaster/man3/BIO_f_base64.html
- OpenSSL 的源代码 - https://github.com/openssl/openssl/blob/d9f073575fdb07b486cd1b38974cd177687ccc1e/apps/rand.c
- BIO 操作中 BIO 的不同排序,这是唯一产生 Base64 输出的配置。
- 为 Base64 BIO 读取输出缓冲区提供比所需更多的内存(以防大小计算错误)。
- 我尝试调用 read() 两次,但第二次调用 returns -1,这显然意味着 BIO 认为没有什么可读的了。
根据我从示例中看到的内容,我所拥有的似乎是正确的。为什么 Base64 过滤器不生成整个字符串?
备注:
这只是一个测试程序,用于了解如何使用 API,因此我不会刷新 BIO。
在我添加
BIO_set_flags(base64_bio, BIO_FLAGS_BASE64_NO_NL)
代码之前,编码错了40个字符...我也不明白。
如有任何帮助或指导,我们将不胜感激。谢谢!
尽管要进行 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 已经完成。