lunes, 13 de octubre de 2014

RSA Authentication

RSA Authentication

The RSA algorithm can be used for encryption and decryption of messages and also for digital signatures.

In order to sign a message, the message must be encrypted using the sender's private key, and then to verify the sign, the cipher text must be decrypted using the public key of the sender.

In this work I have implemented RSA as a login system for a website, instead of passwords the user must sign a message, using the user's private key, and send it the server to be decrypted using the user's public key.

Registration
First of all, the index.html has a form used to register the user and, besides, has the link to the login page.

<html>

  <head>
    <title>Register</title>
  </head>

  <body>
    <h1>Register</h1>
    <a href="rsa.py">Run this script to create keys.</a>
    <form action="cgi-bin/register.py" name="reg" id="reg">
      <br>Choose username: <input type="text" size="10" name="username" id="username" required="True">
      <br><h3>Public Key</h3>
      <br>Enter e: <input type="text" size="10" name="e" id="e" required="True">
      <br>Enter n: <input type="text" size="10" name="n" id="n" required="True">
      <br><input type="submit" value="Enviar"></button>
    </form>
    <br><a href="cgi-bin/login.py">Login</a>
  </body>

</html> 

The user must have a key to register to the system, so I included a script "rsa.py" that generates the public key and the private key. Then, as you can see, the python script register.py is used to register the user.

def register(name, e, n):
   f = open("registered.txt", 'r')
   for line in f:
      userdata = line.split()
      if name == userdata[0]:
         f.close()
         print """The username is not available. Return"""
         return False
   f = open("registered.txt", 'a')
   f.write(name + ' ' + e + ' ' + n + '\n')
   f.close()
   print "The user has been added."
   return True

args = cgi.FieldStorage()
if args.has_key("username") and args.has_key("e") and args.has_key("n"):
   username = args["username"].value
   e = args["e"].value
   n = args["n"].value
   result = register(username, e, n)
   if result == True:
      os.mkdir("users/"+username)
      print """
      
Username: %s
      
       e: %s
      
       n: %s
      
Login with RSA
      """%(username, e, n)  

Log In

The log in system has two purposes verifies the server and verifies the user.
The process is a little explained in the page.

First the user selects a number xc and sends it to the server, both must compute f(x) = x**2 + 1, but the server has to encrypt it using its private key, and then the client decrypts the received f(x) and compares it with the value that f(x).

Meanwhile, the server receives the user name and generates a number x. The user must calculate x**2 + 3*x + 5 and sign it (with the private key). Then that value (s) is sent to the server and is decrypted and compared with the value that the server computed.

This is a piece of the script:
if fields.has_key("username") and fields.has_key("xc"):
   username = fields["username"].value
   xc = int(fields["xc"].value)
   x, e, n = generax(username)
   f = open("rsa.private", 'r')
   privatekey = f.readline().split(",")
   f.close()
   ds = int(privatekey[0])
   ns = int(privatekey[1])
   s = modularExp(fs(xc, ns), ds, ns)

Finally, the script "prove.py" validates the user and, if the user could log in, shows the last time the user had logged in.
if fields.has_key("s"):
   username = fields["username"].value
   x = int(fields["x"].value)
   s = int(fields["s"].value)
   e = int(fields["e"].value)
   n = int(fields["n"].value)
   fx = f(x, n)
   fc = modularExp(s, e, n)
   if fx == fc:
      print "The s is correct this is the user %s"%username
      print """
      

Hi %s

"""%username f = open("users/"+username+"/logins.dat", 'r+') if f.readline() != '': f.seek(0) print " The last time you logged in was", f.readline() else: print " This is the first time you log in" f.seek(0) f.write(asctime()) f.close else: print "Incorrect s. This is not the user. fx != fc" else: print """ Enter s : signed f(x) Return """

The script used to create keys is rsa.py

def rsa():
   try:
      p = getPrime(int(argv[1]))
      q = getPrime(int(argv[1]))
   except:
      p = getPrime(10)
      q = getPrime(10)
   n = p * q
   phin = (p - 1) * (q - 1)
   c = 2
   while c != 1:
      e = randint(2, n-1)
      if phin > e:
         c, x, d = egcd(phin, e)
         h = x * phin + d * e
      else:
         c, d, x = egcd(phin, e)
         h = x * e + d * phin
   if d < 0:
      d %= phin
   print "h=", h, c

   publicKey = (e, n)
   privateKey = (d, n)


Logging in


The index:

 The login:
 Enter s:
 If the user is valid:
 If the user is not valid:


Running rsa.py:
victor@victor-HP-G42-Notebook-PC:~/Downloads$ python rsa.py
h= 1 1
Public Key: (58991, 183467L)
Private Key: (102431L, 183467L)
In the public key the first value is e and the second is n.
Don't share your private key. The first value is d. The second is n.
The keys are stored in rsa.keys

This is the result of running fx.py:
victor@victor-HP-G42-Notebook-PC:~/Downloads$ python fx.py
Introduce x: 7032
Introduce d: 24967
Introduce n: 28601
f(x):  18996
Signed f(x):  2871
 Write this value in the login form

The code is in this repository.

References

Schneier, B. (1996). Applied Cryptography, Second Edition: Protocols, Algorithms and Source Code in C. John Wiley and Sons, Inc.

1 comentario:

  1. + key generation implemented and explained
    + users can register to the service
    + the server is authenticated
    + the user is authenticated
    + the service content distinguishes among users
    + written in English
    + adequate example runs

    => 7 out of 7 possible

    Comments:

    Note that sign != signature.

    La bibliografía podría mejorarse, incluyendo las fuentes sobre python, php, etc., que seguramente consultaste durante el desarrollo de la tarea, pero esta vez lo dejo como advertencia sin multa.

    No pongas los archivos *~ que genera emacs en el Git.

    ResponderEliminar