RSA {1} RSA Keys: What are dQ, dP and InvQ?

Chinese remainder theory

In this case we generate an RSA key pair. With this we have two prime numbers (pp ans qq), and compute the modulus (N=pqN = pq). We then pick ans encryption key value (e=0x010001e = 0x010001) and than compute d=e1(modϕ)d = e^-1\pmod \phi, and where ϕ=(p1)(q1)\phi = (p-1)(q-1). To encrypt a message(MM), we create a cipher c=Me(modN)c = M^e\pmod N, and than decrypt with M=cd(modN)M = cd\pmod N. The key pair also includes dQdQ, dPdP and invQinvQ, and these can be used with the Chinese remainder theory to optimize the decryption process.

New two prime numbers pp and qq

compute the modules

N=pqN = p * q

then pick an encryption exponent ee such that 1<e<φ(N)1 < e < \varphi (N) and then compute:

d=e1(modφ(N))d = e^{-1} \pmod {\varphi (N)}

and where:

φ(N)=(p1)(q1)\varphi (N) = (p-1)(q-1)

The public key is then (e,N)(e, N) and the private key is (d,N)(d, N). To encrypt a message (M)(M), we create a cipher:

C=Me(modN)C = M^e \pmod N

and then decrypt with:

M=Cd(modN)M = C^d \pmod N

The key pair thus contains e,N,d,p,qe, N, d, p, q for a key pair of (e,N)(e, N) and (d,N)(d, N).
It also has the values of dQdQ, dPdP and InvQInvQ. The values of dQdQ is:

dQ=d(modq1)dQ = d \pmod {q-1}

and dPdP is:

dP=d(modp1)dP = d \pmod {p-1}

and InvQInvQ is:

InvQ=q1(modp)InvQ = q^{-1} \pmod p

We can use the values of dQdQ, dPdP and InvQInvQ to speed up the decryption process. The decryption process is:

c=Md(modN)c = M^d \pmod N

To decrypt, we use less complex exponents:

m1=cdP(modp)m_1 = c^dP \pmod p

m2=cdQ(modq)m_2 = c^dQ \pmod q

and then we use the Chinese Remainder Theorem to combine the two values:

h=InvQ(m1m2)(modp)h = InvQ (m_1 - m_2) \pmod p

The recovered message(mm) is then:

m=m2+h×q(modN)m = m_2 + h \times q \pmod N

from cose.keys.rsa import RSA
from cose.keys.cosekey import CoseKey
import binascii
import Crypto.Util.number

import sys



size=512 # 512-bit keys
msg='hello'
if (len(sys.argv)>1):
	size=int(sys.argv[1]) # ValueError: invalid literal for int() with base 10: '--ip=127.0.0.1'

if (len(sys.argv)>2):
	msg=str(sys.argv[2])

M=  bytes_to_long(msg.encode('utf-8'))

cose_key= RSA.generate_key(size)


print ("\ne=",binascii.hexlify(cose_key.e))
print ("n=",binascii.hexlify(cose_key.n))
print ("d=",binascii.hexlify(cose_key.d))
print ("p=",binascii.hexlify(cose_key.p))
print ("q=",binascii.hexlify(cose_key.q))
print ("dp=",binascii.hexlify(cose_key.dp))
print ("dq=",binascii.hexlify(cose_key.dq))
print ("qinv=",binascii.hexlify(cose_key.qinv))

e=int.from_bytes(cose_key.e,byteorder='big')
d=int.from_bytes(cose_key.d,byteorder='big')
p=int.from_bytes(cose_key.p,byteorder='big')
q=int.from_bytes(cose_key.q,byteorder='big')
N=int.from_bytes(cose_key.n,byteorder='big')
dq=int.from_bytes(cose_key.dq,byteorder='big')
dp=int.from_bytes(cose_key.dp,byteorder='big')
qinv=int.from_bytes(cose_key.qinv,byteorder='big')

c=pow(M,e,N)

m1=pow(c,dp,p)
m2=pow(c,dq,q)

h=(qinv*(m1-m2)) %p

m=(m2+h*q) % (N)

res=long_to_bytes(m)

print (f"\nc: {c} m1: {m1}, m2: {m2}, h: {h}, m: {m}")

print ("Decrypted: ",res.decode())