# How do institutions like banks do RSA with big primes?

When encrypting with RSA it is often infeasible to decrypt by just doing c^d mod n, because for example when using the primes $(p,q)=(12553,1233)$, which are small primes compared to those in used by banks, one would often choose the Fermat number $65537$ as public exponent $e$, then the private exponent $d$ is $4267793$, which is a huge number when used as an exponent. How do banks etc. decrypt their data when they choose primes for $p$ and $q$ which are 100s of digits?

-
They use computers which have no problems working with large numbers. –  mikeazo Jan 30 at 19:20
You reduce modulo n after each multiplication. You only need about 1000 squaring and 1000 multiplications (on 1000 bit numbers) when you use square-and-multiply to compute the exponentiation. So the whole thing takes about 1ms total. –  CodesInChaos Jan 30 at 20:02
As an aside, banks probably don't use numbers much larger than most organizations, or even people. They're more cautious about things like key management, but exceptionally strong crypto is widely available these days; it's more of a matter of ensuring your protocols are properly secure instead of picking a insanely high (computational) security level. –  Reid Jan 30 at 22:12
Incidentally, 10^254 is around 2^850. An 850-bit RSA key is awful. It's borderline breakable now. 1024-bit keys are considered deprecated and barely secure; 2048-bit keys are normally used nowadays. –  Matt Nordhoff Jan 31 at 4:17
@fgrieu Sounds pretty close. I get 1.5 ms (660 signs/s) on my 32-bit, four-year-old Xeon, Xen VPS with openssl speed rsa (single-threaded). (13,100 verifies/s, or... 0.076 ms.) –  Matt Nordhoff Feb 1 at 3:02

A lot of them (or their HSM) rely on the Chinese Remainder Theorem to speed up computation for decryption and signing.

To quote Wikipedia:

The following values are precomputed and stored as part of the private key:

• p and q: the primes from the key generation,

• $d_P = d\text{ (mod }p - 1\text{)}$,

• $d_Q = d\text{ (mod }q - 1\text{)}$ and

• $q_\text{inv} = q^{-1}\text{ (mod }p\text{)}$.

These values allow the recipient to compute the exponentiation m = cd (mod pq) more efficiently as follows:

• $m_1 = c^{d_P}\text{ (mod }p\text{)}$

• $m_2 = c^{d_Q}\text{ (mod }q\text{)}$

• $h = q_\text{inv}(m_1 - m_2)\text{ (mod }p\text{)}$

(if $m_1 < m_2$ then some libraries compute $h$ as $q_\text{inv}(m_1 + > p - m_2)\text{ (mod }p\text{)}$)

• $m = m_2 + hq$,

This is more efficient than computing $m ≡ c^d \text{ (mod > }pq\text{)}$ even though two modular exponentiations have to be computed. The reason is that these two modular exponentiations both use a smaller exponent and a smaller modulus.

This is typically the kind of things you may find implemented in smart cards or in constrained devices.

-
do you have any sources to back up your claim that banks do this (not saying you are wrong, just that a source would add credibility). –  mikeazo Jan 31 at 13:12
1) CRT is only a factor 4 speedup. The OP has trouble understanding why modular exponentiation has anywhere near acceptable performance, a factor 4 is irrelevant in this context. 2) Larger devices will use CRT as well. It's just as nice on a large x86/AMD64 as it is on a constrained device. –  CodesInChaos Jan 31 at 13:28

When calculating terms in the form of a ^ b mod c most libraries for arbitrary sized integer calculations (e.g. Java's BigInteger) use a special algorithm instead of first doing the exponentiation and then doing the modulo (since storing the result of $a^b$ with 4096-bit keys would require more RAM than even todays biggest computers have).

So this is how Java does it when a ^ e mod m is to be calculated (Pesudo-code):

1. If $e$ is negative return modInverse(a, m) ^ -e mod m
2. If $e = 1$ the exponentionation can be ignored and the simple modulo is calcualted.
3. $s=1$
4. While $e$ is not $0$

1. s = s * t mod m
2. e = floor(e / 2) (bitshift to the right by 1)
3. a=a * a mod m
5. a is the result.

-
You never defined $t$... –  figlesquidge May 1 at 17:11
Sorry for this, $t=a$ –  marstato May 2 at 16:13
Fair enough. However, it sounds like your algorithm will give the same output for $e=\mathtt{0b1000}$ and $e=\mathtt{0b1011}$. that is, I can't see anywhere why you use the actual values of $e$, rather than just it's bit-length –  figlesquidge May 2 at 16:15
I just transcribed the code for the method modPow of Javas BigInteger class as seen here: link –  marstato May 2 at 18:32

First of all to encrypt/decrypt data such institutions as banks use some block or stream ciphers for instance AES (Advanced Encryption Standard), which are very fast compared to RSA algorithm, hundreds times faster to process same amount of data. But block and stream ciphers use symmetric key (which is usually 128-256 bits random number, much smaller than RSA keys), it means that both parties A and B who exchange data encrypted with ciphers need to have same symmteric key and for that they need to share securely this key.

To exchange a symmetric key an asymmetric encryption is used. RSA is an example of an asymmetric encryption system. Most asymmetric encryption systems are much slower than symmetric ciphers, mostly due to usage of big numbers (as you mentioned) in computation.

So to exchange a shared symmetric key, used to encrypt large amount of data, we encrypt this key using RSA public key of recipient. Because only small key (e.g. 256 bits long) is encrypted using RSA, quite small amount of time (e.g. 0.5-1 second) is used for that. After that large symmetrically encrypted data and small asymmetrically (using RSA) encrypted key are send to recipient. On the recipient side the opposite is done - first the symmetric key is decrypted using RSA private key and second large data is decrypted using symmetric key with block or stream cipher like AES.

Also usually some integrity check is done, e.g. by using MAC (Message Authentication Code) - MAC is computed on sender side and checked on recipient side. Or instead of MAC a digital signature (using e.g. DSA, Digital Signature Algorithm) is create on sender's side using sender's private key and verified on recipient's side using sender's public key. MAC is an integrity check value created using symmetric algorithms (e.g. AES, 3DES), while digital signature is created using asymmetric algorithms (e.g. RSA or DSA).

To answer your question about large numbers - in order to compute those large exponents by some large modulus arbitrary length big numbers simulation is done with numbers having thousands of bits, i.e. around one thousand decimal digits. I'll give an example of how exponentiation can be computed in a quite fast way instead of straightforward multiplication (which can take forever). All the multiplications, additions, subtractions and divisions are simulated as a huge numbers arithmetic in the memory using algorithms similar to those that we studied at school to e.g. multiply or divide long numbers on paper. To do a fast exponentiation a technique called Exponentiation by Squaring is used. We will compute value of C = M^E (mod N). This algorithm is proportional to the number of bits in exponent E, i.e. does several big number operations (approximately two multiplies and two divisions) per each bit in number E, so if E is from 1024 to 2048 bits (these lengths are usual for RSA) then algo makes around 1024 to 2048 blocks of 2 to 4 arithmetic operations on big numbers. There are two main versions of that algorithm exist, one is iterating through bits of exponent left to right (MSB-first (Most Significant Bit first) order), another one is iterating right to left (LSB-first (Least Significant Bit first) order) (cited from here):

// LSB Binary Exponentiation Algorithm (scans exponent's E bits right to left)
// Input: Exponent: E of k bits, message M
// Output: Ciphertext: C = M^E (mod N)
C =1 ; S = M;
// Scan E's bits from LSB to MSB (right to left).
for i := 0 to k-1
begin
// Multiply by degree of M.
if (E_i = 1) C = C * S (mod N);
// Square degree of M.
S = S * S (mod N);
end;

// MSB Binary Exponentiation Algorithm (scans exponent's E bits left to right)
// Input: Exponent: E of k bits, message M
// Output: Ciphertext: C = M^E (mod N)
C = 1;
// Scan E's bits from MSB to LSB (left to right).
for i := k-1 downto 0 do
begin
// Square result.
C = C * C (mod N);
// Multiply by M if E's bit is set.
if (E_i = 1) C = C * M (mod N);
end;

-