/* $Id: t_dibigdRSAEncrypt.cpp $ */
/*
* Copyright (C) 2026 David Ireland, D.I. Management Services Pty Limited
* <https://di-mgt.com.au/contact/> <https://di-mgt.com.au/bigdigits.html>
* SPDX-License-Identifier: MPL-2.0
*
* Last updated:
* $Date: 2026-05-05 02:02 $
* $Revision: 1.0.1 $
* $Author: dai $
*/
/* Encrypt data using RSA PKCS#1 v1.5 standard */
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <iostream>
#include <string>
#include <iomanip>
#include <stdexcept>
#include <vector>
#include <assert.h>
#include <time.h>
#include "dibigd.hpp"
using std::cout;
using std::endl;
using namespace dibigd;
/* Hard code the RSA key values */
// Bob's public encryption key from RFC9216
BigDigit n =
"0xE67005D20951A1FF4D8C12A47BA83E"
"ED12EB3A045FC108DC1FEDB39B401FEB"
"B14944DAC4C13B8EBAD9566A6500DE9F"
"7EC1BED7AA2CD51CE42155EB23C20A7C"
"3C9A68F00766F1AAFCE1DDADB5ECB539"
"577168226E35EED22637EBC12841E8DB"
"C09BB4BC0831B7F846A990EF5FCE7DA9"
"5B0691110EADC16B478B5413E753DDB9"
"1B62435A2AB2E264F0B04381431994A5"
"2C6977C5F062B32651AE68B465E7FDCA"
"7EBF7E6FA564083BB14D960B671B7AF9"
"ADFF424682DC8F66DB280FB9BB471490"
"793F9FACF1BA113922A6D4E07582C2E8"
"C3C785F52ECEB5C1867A8A1926225440"
"2475E0D694E5B2327CA119576612B57C"
"1DCEDA04249D9F4544482BEF189F0941"
"DD";
BigDigit e(0x10001);
// Bob's private key
BigDigit d =
"0x05C420D5F4ED89E67E3BF68D754D78F4"
"D2B4AB1F7B18B4C18C882E4040C30551"
"4ADA5BB83E1060F40760014A8B1F53C4"
"F9EABAE49686670BC51FC5F532CD802A"
"247362C3CE408A09E27D6173AF6E8843"
"7D62472FE101CEBEFAAD0AD5988C9C9B"
"E41CBD58F78B1FA4329C9E85941A12AB"
"18544525B261F4EEC2AB75387121B14B"
"877773790666C589104D8F868803DCF3"
"FA2E712F49B7DE430A6A2FC08E3DEC23"
"4009B19E595408586C2F2C0ADD577AF6"
"FA8B8D69F52E864B0182D7D6F2FB5CBD"
"582D501AD6F9183A2DBC284CBE6652FC"
"EDCD78373AC42FCB66841C1CD5608997"
"7B7F583A88490994260AF83EF1B1DED8"
"EB7D30EF91DA8F4BE796188939B480FB";
BigDigit p =
"0xF1BFC8E9D83E885511A061F6829D45"
"37320EF4C1A817D5F80F1CEF5293A7BD"
"73C0A0391876BB05A3A536B0BBCF3104"
"617267EC675AAAFB18236C96D6ACDE6F"
"78AE2E00E11F78FB9B8BF3EA0E2C2DBA"
"80C0DFCC04DDD50DE4FE1F75F582E4F3"
"DB689D01146C215925DA614E111BBE0D"
"96FA736C1157101AE0A5CE15F403218C"
"B3";
BigDigit q =
"0xF4058937B1D1906C103F8580F5118B"
"197D879B52262FDA54ED5464604E884A"
"15C9510163AD18FF5845B2B21159012E"
"18E0917CD2F711AA2B2C0FEF5CFD227C"
"BECC319BCE4F04941FE0952EC61465F9"
"D131B42127DA1564D8771B7898DF6976"
"E644D9B953FF6EAEC94F035C2101845F"
"CEAA1C108C9A8A4D84D3465DC0ADAE5F"
"2F";
BigDigit dP =
"0xD0C95B632320F6ABC9DA6360FC7389"
"A8DEF1EDCF2736D6D4337140FC678BD2"
"629B3585BA2C28DFF8F2A26646FDED8E"
"A3FEA3E4976AC60AB0513FE2922BA0BC"
"5354D3646D09BA7A4B5FB6DC293B5C8F"
"1BCDF83B02E4F7B1D558E8A0FED5FA98"
"E5A0D7206C9BEABD4CA4EBAEF9B5A511"
"A5984E81420498632E2BE4EE2EDD5967"
"63";
BigDigit dQ =
"0xA507816F5B20E14D5407C1A01F1D48"
"376AFFE4F93FBE29283A815289175370"
"D71F195B992F9DB242DE90258139F264"
"5C8AB399F98B023555912D0DB293B759"
"2A282A7CB6A015F69F4061640AAE0CF1"
"509B0EB9459C65CF97DDA5847FCEC822"
"934489029F5E265AAAE676DD3DAD2AFB"
"28673F27AA0F71ED4F211B7B982D5DBA"
"1D";
BigDigit qInv =
"0x2389FC2DB5C96DB93706791547613EC4"
"26547EFE63274968BCC74BF73B3EB3A0"
"40544C75E8EF024BBF79825B29B52FEE"
"AB091481B88BF206D027D59AEFC16B1E"
"5F6DF619B6807FD33C5668B908112B55"
"59A2AB48A45D4EB3734C03AB79E24AB1"
"8E11369EABBE6A60A236E62060354E0F"
"0CBA9D3143C178776F2BB547B29C7C73";
void do_test() {
cout << "Encrypt data using RSA PKCS#1 v1.5 standard." << endl;
cout << "============================================" << endl;
std::string msg ="abc"; /* Default message */
size_t msglen = msg.length();
// We will encrypt a message msg and send to Bob, encrypting using Bob's public key.
cout << "Encrypting a message to Bob..." << endl;
cout << "Message to encrypt is '" << msg << "' " << msglen << " bytes long." << endl;
size_t nbits = n.bitlen();
cout << "Bob's public key is " << nbits << " bits long" << endl;
/* Create a PKCS#1 v1.5 EME message block in octet format */
/*
|<-----------------(klen bytes)--------------->|
+--+--+-------+--+-----------------------------+
|00|02|PADDING|00| DATA TO ENCRYPT |
+--+--+-------+--+-----------------------------+
The padding is made up of _at least_ eight non-zero random bytes.
*/
/* How big is the key in octets (8-bit bytes)? */
size_t klen = (nbits + 7) / 8;
/* Set up encryption block of klen bytes */
std::vector<unsigned char> block(klen);
/* Set fixed byte values */
block.at(0) = 0x00;
block.at(1) = 0x02;
block.at(klen - msglen - 1) = 0x00;
// Length of random padding string
size_t padlen = klen - msglen - 3;
assert(padlen >= 8);
// Fill with nonzero random bytes 0 < r < 256
BigDigit r;
for (size_t i = 0; i < padlen; i++) {
while (r.set_rand_number(256) == 0) {
;
}
block.at(i + 2) = (unsigned char)(r.to_short() & 0xff);
}
// Copy the raw bytes from the msg string (yuk!)
unsigned char* raw = reinterpret_cast<unsigned char*>(const_cast<char*>(msg.c_str()));
for (size_t i = 0; i < msglen; i++) {
block.at(padlen + 3 + i) = raw[i];
}
Bvec::print_hex("block, m=\n", block);
/* Convert block byte array to a big integer m */
BigDigit m = from_octets(block);
/* Encrypt c = m^e mod n */
BigDigit c = m.mod_exp(e, n);
c.printhex("c=");
/* Check decrypt m1 = c^d mod n */
cout << "About to decrypt..." << endl;
clock_t start = clock();
BigDigit m1 = c.mod_exp(d, n);
clock_t finish = clock();
m1.printhex("m'=");
bool ok = (m1 == m);
cout << "Decryption " << (ok ? "OK" : "FAILED!") << endl;
assert(m1 == m);
double interval = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "Decryption by inversion took " << interval << " seconds" << endl;
/* Extract the message bytes from the decrypted block, exactly klen bytes */
block = m1.to_octets(klen);
Bvec::print_hex(block);
assert(block.at(0) == 0x00);
assert(block.at(1) == 0x02);
size_t i;
for (i = 2; i < block.size(); i++) {
// Look for zero separating byte
if (block.at(i) == 0x00)
break;
}
if (i < klen) {
cout << "Decrypted message is '";
size_t nchars = klen - i - 1;
for (size_t j = 0; j < nchars; j++) {
cout << block.at(i + 1 + j);
}
cout << "'" << endl;
}
else {
cout << "ERROR: failed to find message in decrypted block" << endl;
}
/* Decrypt using CRT method - Ref: PKCS #1/RFC8017 */
cout << "Decrypting by CRT method..." << endl;
start = clock();
/* Let m_1 = c^dP mod p. */
BigDigit m_1 = c.mod_exp(dP, p);
/* Let m_2 = c^dQ mod q. */
BigDigit m_2 = c.mod_exp(dQ, q);
/* Let h = qInv ( m_1 - m_2 ) mod p. */
BigDigit h = qInv.mod_mult(m_1.mod_sub(m_2, p), p);
/* Let m = m_2 + hq. */
m1 = m_2 + h * q;
m1.printhex("m'=");
finish = clock();
assert(m1 == m);
interval = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "Decryption by CRT took " << interval << " seconds" << endl;
}
int main() {
/* MSVC memory leak checking stuff */
#if _MSC_VER >= 1100
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
#endif
/* Catch any exceptions */
try {
do_test();
}
catch (const std::exception& e) {
// Handle standard exceptions with a specific message
std::cerr << "Standard exception: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Caught unknown exception." << std::endl;
}
cout << endl << "ALL DONE." << endl << endl;
return 0;
}