[Back] This is a fun page of creating an RSA signature in just 12 lines of Python (not including import statements). With this we use the decryption key value to encrypt for a signature, and the public key to prove the signature. In this case, we use \(s\) as the signing exponent (which would be defined as \(d\) for decryption), and \(v\) for the verification exponent (which would be defined as \(e\) for encryption). We have two secret prime numbers (\(p\) and \(q\)), and which produces a product \(N=pq\). In this case we will sign a hash of the message. [Signing with message.]

## RSA in 12 lines of Python (Signing with hash) |

## Outline

With this we use the decryption key value to encrypt for a signature, and the public key to prove the signature. In this case, we use \(s\) as the signing exponent (which would be defined as \(d\) for decryption), and \(v\) for the verification exponent (which would be defined as \(e\) for encryption). Alice initially has two secret prime numbers (\(p\) and \(q\)), and which she produces a product (the modulus):

\(N=pq\)

Next, she selects a *verification exponent* (\(v\)), and which does not share a factor with:

PHI=(p-1)(q-1)

In most cases she will select:

\(v=65537\)

Next she computes the *signature exponent* (\(s\)) with:

\(sv = 1 \pmod {(p-1)(q-1)}\)

Next she takes a message (\(D\)) and sign with:

\(S=D^s \pmod N\)

Bob then checks the signature with:

\(M=S^v \pmod{N}\)

If \(M\) is equal to \(D\), the signature matches.

This works because of Euler's formula, where:

\(S^v = D^{sv} = D \pmod N\)

## Coding

The coding is here:

from Crypto.Util.number import * from Crypto import Random import Crypto import gmpy2 import sys import hashlib import binascii bits=60 msg="Hello" if (len(sys.argv)>1): msg=str(sys.argv[1]) if (len(sys.argv)>2): bits=int(sys.argv[2]) p = Crypto.Util.number.getPrime(bits, randfunc=Crypto.Random.get_random_bytes) q = Crypto.Util.number.getPrime(bits, randfunc=Crypto.Random.get_random_bytes) n = p*q PHI=(p-1)*(q-1) v=65537 s=(gmpy2.invert(v, PHI)) D = bytes_to_long(hashlib.md5(msg).hexdigest()) S=pow(D,s, n) res=pow(S,v ,n) print "Message=%s\np=%s\nq=%s\n\ns=%d\nv=%d\nN=%s\n\nSigning exponent (s,n)\nVerification exponent (v,n)\n\nSignature=%s\nCheck=%s (original hash=%s)" % (msg,p,q,s,v,n,S,res,(D % n))

A sample run:

Message=hello p=1142174655856866103 q=646382400791262259 s=428299529832002056187975682522486833 v=65537 N=738281596175694866501638653320306677 Signing exponent (s,n) Verification exponent (v,n) Signature=138695930372262568164566883289398201 Check=76320072942423965607394202493248868 (original hash (mod N)=76320072942423965607394202493248868)