Skip to content

Instantly share code, notes, and snippets.

@rubpy
Last active July 29, 2022 20:53
Show Gist options
  • Save rubpy/84b59da6970c764ebefab096c253c172 to your computer and use it in GitHub Desktop.
Save rubpy/84b59da6970c764ebefab096c253c172 to your computer and use it in GitHub Desktop.
encrypt_with_bear - a handy wrapper for the low-level BearSSL RSA encryption API
#include <bearssl.h>
#include <derdec.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* (RSA-2048)
-----BEGIN PUBLIC KEY-----
MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBez9MX9NzGasT/wlMKgLPL
Ct3zg+OmlJmP+QgRSkbfF4bgwlRqrgboyTH1kdtKJ6+DmiazbKHkLMhJuleofkKl
ftbO7T7epaJG6wSrM3LDflbOPcThKOeSp1Qg0JKRgllCxzHgS6rcyO4+5vNkeWnh
biNTrBInUe7PCpk7NuRRKjH8Um5hTqRvH1WxfO9gvqPj5y4jUhZs9A/Uv78NPNbi
9i3DPPN2VIa13DUL5v1CufZdZ0EaSnFV0MIgRJiYUg6KRFM9tU4HNwm85ePrB36L
QOp1LYAsQuGvvr50b8n3E+WOyNEadKHnMlMtY5EMP1XKoL646EC3jBOL1aVuIfVv
AgMBAAE=
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQBez9MX9NzGasT/wlMKgLPLCt3zg+OmlJmP+QgRSkbfF4bgwlRq
rgboyTH1kdtKJ6+DmiazbKHkLMhJuleofkKlftbO7T7epaJG6wSrM3LDflbOPcTh
KOeSp1Qg0JKRgllCxzHgS6rcyO4+5vNkeWnhbiNTrBInUe7PCpk7NuRRKjH8Um5h
TqRvH1WxfO9gvqPj5y4jUhZs9A/Uv78NPNbi9i3DPPN2VIa13DUL5v1CufZdZ0Ea
SnFV0MIgRJiYUg6KRFM9tU4HNwm85ePrB36LQOp1LYAsQuGvvr50b8n3E+WOyNEa
dKHnMlMtY5EMP1XKoL646EC3jBOL1aVuIfVvAgMBAAECggEAIvBlMyPaJAh+ll2v
KmSpXP6hMjb9Mor6WBMGhRChM19BJhyW7UU6aJiUH5HjhN1BEbdB4cb7ldFm8byI
xx/YQZKPaGwHShcxyP6cltZ7yU0KgjBDGFJxnBqrpvgVuyeU60XqvGRGD9y/51BG
i1UuzpM+03vKqNDJt2SJeUfONZZq5Qg/EAws+HMR5zPtERsNk7IMxVOb0AEs7ORD
fU46MZnbaYi9c7tp8u8n0xJHtGXr1WoY8q0alfDKn65Hkz1PxMQ9x4jPaZUtvf/j
gZkk4jyNwcevlUdE3kp9mFdfcL4YA0uMiEnqS66uygYF4B+xYNPNO39gdy+6Fuz2
XJuJqQKBgQCpHYXsh2P+m+pXzIKrV6/g/JEdUXN21k/pTi2Zoq/LEYZrmV9J7qSE
qonGFWifLDsokk0qvlAp9uVID5gnWH+P+vmeEOktfISZcH6B03haGGYL6LLqNhwG
BuTawmLbfxCLXB/CUjtxuBbtCETHAD+IWImJMNyFXE2wy4ysdxVl2wKBgQCPhbcV
a8UMqMvLO/kxOw51Ehm3ENnEYpMC1bgJeq/neP1lKnJ/Ir7RzNAWjoG655gqy0L6
a48e8Scw65iN2mcjQuXPtYfikfZcH/OStX3sQ8ac45L7qy4C7+jY4qQhwseXnuFT
AVo+S/4AEgKwlYyQm110WrQJ5XGygk5zHPSk/QKBgEUkr/vcAzM3NiH9mLNLX7qC
KSauhaHhz7xY3WYCUROar7XQeFg2/QbM3xWg7SyfHfThlDFUrFvr+SR0U8ZKdaU9
fM92pI+XaHN/vgmAl6VmclqOIpCF3QFN0kXq0hZiJjaETOvbSTiehqkVB2HBpTgu
0tTHqHHSImWVY4ekDJifAoGAOPOgoRlwygM5S15zFfwPUplqJuDC6VEMcTWJoAlV
QA8czkY3xQdunSYe9LR7+kTodyLNYz3HP0oGeT0j/jZKcw2az/+C+n9dOVVcfD0U
yOpkJ+GOc9uLmJLG3TmiU9tNBHeBhkSlIM9a7YA4HQZbDw732LIde0fXBDT9GGTH
F6kCgYEAoibOpeO4NMq8pzFdK9ahGXLgk7ECW+Bk5gXvgLvUdLIMqxKy0hkOTtbn
sN75ZEKc5vQzqmiIl9gBR9hVcKwFR7jUH1I3KOdwJc0qxenWe4ZhAj9PDOrhKuDD
cqAdRAy5UN2TSpU4AWaF5qpfk2Dorjy+ytqpKGY9QBxjPDaygNA=
-----END RSA PRIVATE KEY-----
*/
static const uint8_t sample_raw_pkey[] = {
0x30, 0x82, 0x01, 0x21, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0e, 0x00,
0x30, 0x82, 0x01, 0x09, 0x02, 0x82, 0x01, 0x00, 0x5e, 0xcf, 0xd3, 0x17,
0xf4, 0xdc, 0xc6, 0x6a, 0xc4, 0xff, 0xc2, 0x53, 0x0a, 0x80, 0xb3, 0xcb,
0x0a, 0xdd, 0xf3, 0x83, 0xe3, 0xa6, 0x94, 0x99, 0x8f, 0xf9, 0x08, 0x11,
0x4a, 0x46, 0xdf, 0x17, 0x86, 0xe0, 0xc2, 0x54, 0x6a, 0xae, 0x06, 0xe8,
0xc9, 0x31, 0xf5, 0x91, 0xdb, 0x4a, 0x27, 0xaf, 0x83, 0x9a, 0x26, 0xb3,
0x6c, 0xa1, 0xe4, 0x2c, 0xc8, 0x49, 0xba, 0x57, 0xa8, 0x7e, 0x42, 0xa5,
0x7e, 0xd6, 0xce, 0xed, 0x3e, 0xde, 0xa5, 0xa2, 0x46, 0xeb, 0x04, 0xab,
0x33, 0x72, 0xc3, 0x7e, 0x56, 0xce, 0x3d, 0xc4, 0xe1, 0x28, 0xe7, 0x92,
0xa7, 0x54, 0x20, 0xd0, 0x92, 0x91, 0x82, 0x59, 0x42, 0xc7, 0x31, 0xe0,
0x4b, 0xaa, 0xdc, 0xc8, 0xee, 0x3e, 0xe6, 0xf3, 0x64, 0x79, 0x69, 0xe1,
0x6e, 0x23, 0x53, 0xac, 0x12, 0x27, 0x51, 0xee, 0xcf, 0x0a, 0x99, 0x3b,
0x36, 0xe4, 0x51, 0x2a, 0x31, 0xfc, 0x52, 0x6e, 0x61, 0x4e, 0xa4, 0x6f,
0x1f, 0x55, 0xb1, 0x7c, 0xef, 0x60, 0xbe, 0xa3, 0xe3, 0xe7, 0x2e, 0x23,
0x52, 0x16, 0x6c, 0xf4, 0x0f, 0xd4, 0xbf, 0xbf, 0x0d, 0x3c, 0xd6, 0xe2,
0xf6, 0x2d, 0xc3, 0x3c, 0xf3, 0x76, 0x54, 0x86, 0xb5, 0xdc, 0x35, 0x0b,
0xe6, 0xfd, 0x42, 0xb9, 0xf6, 0x5d, 0x67, 0x41, 0x1a, 0x4a, 0x71, 0x55,
0xd0, 0xc2, 0x20, 0x44, 0x98, 0x98, 0x52, 0x0e, 0x8a, 0x44, 0x53, 0x3d,
0xb5, 0x4e, 0x07, 0x37, 0x09, 0xbc, 0xe5, 0xe3, 0xeb, 0x07, 0x7e, 0x8b,
0x40, 0xea, 0x75, 0x2d, 0x80, 0x2c, 0x42, 0xe1, 0xaf, 0xbe, 0xbe, 0x74,
0x6f, 0xc9, 0xf7, 0x13, 0xe5, 0x8e, 0xc8, 0xd1, 0x1a, 0x74, 0xa1, 0xe7,
0x32, 0x53, 0x2d, 0x63, 0x91, 0x0c, 0x3f, 0x55, 0xca, 0xa0, 0xbe, 0xb8,
0xe8, 0x40, 0xb7, 0x8c, 0x13, 0x8b, 0xd5, 0xa5, 0x6e, 0x21, 0xf5, 0x6f,
0x02, 0x03, 0x01, 0x00, 0x01,
};
static const size_t sample_raw_pkey_len = sizeof(sample_raw_pkey);
// --------------------------------------------------
// clang-format off
/**
* A handy wrapper for the low-level BearSSL RSA encryption API.
*
* On success, returns 0.
* On failure, returns a non-zero value (e.g., -1).
*
* === Usage ===
*
* ```c
*
* int main(void) {
* derdec_pkey pkey;
*
* // derdec_decode_pkey(&pkey, ...);
* // ...
*
* const char *plaintext = "hello world";
* uint8_t buf[256];
*
* if (encrypt_with_bear(
* buf,
* sizeof(buf),
* plaintext,
* strlen(plaintext),
* &pkey) != 0) {
* fprintf(stderr, "[!] encrypt_with_bear failed\n");
*
* return 1;
* }
*
* for (size_t i = 0; i < sizeof(buf); ++i) {
* printf("%02x", buf[i]);
* }
* printf("\n");
*
* return 0;
* }
*
* ```
*
*/
// clang-format on
int encrypt_with_bear(uint8_t *buf, size_t buf_len, const char *const plaintext,
size_t plaintext_len, const derdec_pkey *const pkey) {
if (buf == NULL || buf_len != 256 || plaintext == NULL ||
plaintext_len == 0 || pkey == NULL) {
// ERROR: invalid arguments.
return -1;
}
memset(buf, 0, buf_len);
if (plaintext_len > 245) {
// ERROR: plaintext is too long.
return -2;
}
if ((pkey->modulus.start == NULL || pkey->modulus.end == NULL) ||
(pkey->exponent.start == NULL || pkey->exponent.end == NULL)) {
// ERROR: invalid public key given.
return -3;
}
if (derdec_pkcs1(buf, buf_len, (const uint8_t *)plaintext, plaintext_len,
0) != DERDEC_OK) {
// ERROR: PKCS#1 encoder has failed.
return -4;
}
const br_rsa_public_key pkey_bear = {
(unsigned char *)derdec_pkey_modulus(pkey),
derdec_pkey_modulus_size(pkey),
(unsigned char *)derdec_pkey_exponent(pkey),
derdec_pkey_exponent_size(pkey),
};
br_rsa_public rsa_pub_engine = br_rsa_public_get_default();
if (!rsa_pub_engine(buf, buf_len, &pkey_bear)) {
// ERROR: BearSSL's RSA-2048 encryption engine has failed.
return -5;
}
// OK: plaintext has been encrypted successfully. Result was saved into `buf`.
return 0;
}
// --------------------------------------------------
int main(void) {
derdec_pkey pkey;
derdec_err err;
if ((err = derdec_decode_pkey(&pkey, sample_raw_pkey, sample_raw_pkey_len)) !=
DERDEC_OK) {
fprintf(stderr, "[!] derdec_decode_pkey failed: %s\n", derdec_err_str(err));
return 1;
}
if (!derdec_pkey_is_pkcs1(&pkey)) {
fprintf(stderr, "[!] pkey is not a PKCS1 public key\n");
return 2;
}
const char *plaintext = "hello world";
uint8_t buf[256];
if (encrypt_with_bear(buf, sizeof(buf), plaintext, strlen(plaintext),
&pkey) != 0) {
fprintf(stderr, "[!] encrypt_with_bear failed\n");
return 3;
}
for (size_t i = 0; i < sizeof(buf); ++i) {
printf("%02x", buf[i]);
}
printf("\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment