I am interfacing with Mega.co.nz's API, using a python library as a reference and this code is throwing. The private key is of a temporary account.
When I only use the first prime it works, but if I include the second one it throws, yet everything works fine in the python code.
This code throws "CryptoMaterial: this object contains invalid values"
// g++ test.cpp -o test -lcryptopp
#include <iostream>
#include <cryptopp/rsa.h>
#include <cryptopp/integer.h>
#include <cryptopp/osrng.h>
using namespace CryptoPP;
const Integer c("10857166326382703760062779528766843368820930576598213227278471554906214169288262514203969639120532785228356073660117311791556795787311220009132632364495267243081665670086710276242234063736282452747089977833464270310556099739736793916154923086192702968111366046442015937417526298511445199340095898060147092158884693079554126699550560654798428433227449793922222881580173315635171540012289392792883134869370184160735204631001817822007869637755937740560912176149892518538187132538381475906064954503330035090788011376816518843886790979724470958150966813982521146398987188066116582925811581312709558507015381360737728282160");
const Integer n("13427557315502247597000078151163920443026153459996461135918747863095898679484680068841870307134991870634527490898047374333864169992533593470214214321618599580908993204307520436691605704402046321917552215500601059547120681142391461211832942043578807378527059669212765719156841060911214035328326209517003764423649629080809193207761562938380209994488934153009055462878017442054432223170713164757958714200660834201842865647297155663529615291314825578660639925675604438589594375258126020834604025620095899336598293228999530739615479725715448390873778015506002443516234879727296164834962067569248938506798206172807824155467");
const Integer d("11307416686738734818526381600980143530969392387365440956563156095238651519566046373761574995482098417376444202861513578386411932625291447132811969955047241752344415329943175104582404803706986376351622918316295629092312152540961230494175109089329522002970155510916013237184708261819969713960695755382740012146034212919647492076234405993178655740138052420647985859442037931597940897198569337697554456337486998070498389971468780232363941255237291940175758993311124407117751983734467699346428299766707608212611622303248258864115688090242455959830749262966169383160757942327094420226154106561552020347355716010319448907163");
const Integer p("100826948907457598414845964524448089304988432540271591225687687675999370502892903258891517574080931665624511494151970577170497712420499991942965423848183374943909439781466449525683097361603853112400332604761081878780250618758818492357490355994233490146112828080518628573284802902011591132699377690748913996743");
const Integer q("133174289820338768818359856956108213770008470949300663564909710605878037244519172983221279725814092327501516062026008560426937338300041407758960697270460830193354454791979178335037322285526761471721659139131141459697849499793713446217272909739442810866721995133352912243119263125394323211613915719804564581469");
int main(){
AutoSeededRandomPool prng;
InvertibleRSAFunction rsa;
rsa.SetModulus(n);
rsa.SetPrivateExponent(d);
rsa.SetPrime1(p);
rsa.SetPrime2(q); // Works fine if this line is removed
RSA::PrivateKey privKey(rsa);
Integer r = privKey.CalculateInverse(prng, c); // Throws here
std::cout << "r: " << r << std::endl;
return 0;
}
But this python code works:
from Crypto.PublicKey import RSA
c = 10857166326382703760062779528766843368820930576598213227278471554906214169288262514203969639120532785228356073660117311791556795787311220009132632364495267243081665670086710276242234063736282452747089977833464270310556099739736793916154923086192702968111366046442015937417526298511445199340095898060147092158884693079554126699550560654798428433227449793922222881580173315635171540012289392792883134869370184160735204631001817822007869637755937740560912176149892518538187132538381475906064954503330035090788011376816518843886790979724470958150966813982521146398987188066116582925811581312709558507015381360737728282160L
n = 13427557315502247597000078151163920443026153459996461135918747863095898679484680068841870307134991870634527490898047374333864169992533593470214214321618599580908993204307520436691605704402046321917552215500601059547120681142391461211832942043578807378527059669212765719156841060911214035328326209517003764423649629080809193207761562938380209994488934153009055462878017442054432223170713164757958714200660834201842865647297155663529615291314825578660639925675604438589594375258126020834604025620095899336598293228999530739615479725715448390873778015506002443516234879727296164834962067569248938506798206172807824155467L
d = 11307416686738734818526381600980143530969392387365440956563156095238651519566046373761574995482098417376444202861513578386411932625291447132811969955047241752344415329943175104582404803706986376351622918316295629092312152540961230494175109089329522002970155510916013237184708261819969713960695755382740012146034212919647492076234405993178655740138052420647985859442037931597940897198569337697554456337486998070498389971468780232363941255237291940175758993311124407117751983734467699346428299766707608212611622303248258864115688090242455959830749262966169383160757942327094420226154106561552020347355716010319448907163L
p = 100826948907457598414845964524448089304988432540271591225687687675999370502892903258891517574080931665624511494151970577170497712420499991942965423848183374943909439781466449525683097361603853112400332604761081878780250618758818492357490355994233490146112828080518628573284802902011591132699377690748913996743L
q = 133174289820338768818359856956108213770008470949300663564909710605878037244519172983221279725814092327501516062026008560426937338300041407758960697270460830193354454791979178335037322285526761471721659139131141459697849499793713446217272909739442810866721995133352912243119263125394323211613915719804564581469L
rsa_decrypter = RSA.construct( (n, 0L, d, p, q) )
print( rsa_decrypter.key._decrypt(c) )
I checked the source. the exception is throw from RSAFunction::Validate
, because e
is not set.
However, setting e
doesn't fix it, as then it is also thrown from InvertibleRSAFunction::Validate
because dp
, dq
, and u
are not set.
An RSA private key minimally only requires N, D. However, usually there are additionally the five integers P, Q, DP, DQ, QP. These extra integers are intermediate steps which make the calculation much faster. It is possible but very slow to do the calculation just using N and D. (You basically have to do log2(D) times as many calculations).
E is required for a public operation; but typically a private key is published as a key pair which includes E.
The Crypto++ private key operation also uses E however: it does some extra steps involving random data, which I presume is to prevent timing attacks.
I'd guess that the Python version works because it does not do this timing attack prevention; and it also computes any values that were missing. (They can all be computed from N
and D
as I mentioned, but this is slow).
Here is additional code to compute the missing values for yourself, this works for me:
rsa.SetModulus(n);
rsa.SetPrivateExponent(d);
rsa.SetPrime1(p);
rsa.SetPrime2(q);
// add this:
rsa.SetModPrime1PrivateExponent( d % (p-1) );
rsa.SetModPrime2PrivateExponent( d % (q-1) );
rsa.SetMultiplicativeInverseOfPrime2ModPrime1( q.InverseMod(p) );
rsa.SetPublicExponent( d.InverseMod((p-1) * (q-1)) );
Note that in general, private key files should contain all of these values - it's unusual (to me, anyway) that you would be sitting there with N,D,P,Q but not the others.