created session class to hold aa, bb and so forth - done for client
authorAzul <azul@riseup.net>
Thu, 4 Oct 2012 09:23:00 +0000 (11:23 +0200)
committerAzul <azul@riseup.net>
Thu, 4 Oct 2012 09:41:53 +0000 (11:41 +0200)
We have a session in the server already - duplication there now, merge next

lib/ruby-srp.rb
lib/srp/authentication.rb
lib/srp/client.rb
lib/srp/session.rb [new file with mode: 0644]
lib/srp/util.rb

index d5d6cf3..383cbca 100644 (file)
@@ -11,6 +11,7 @@ module SRP
   autoload :Client, 'srp/client'
   autoload :Authentication, 'srp/authentication'
   autoload :Util, 'srp/util'
+  autoload :Session, 'srp/session'
   class WrongPassword < StandardError
   end
 end
index 3428fd4..c87fe1d 100644 (file)
@@ -17,7 +17,7 @@ module SRP
       end
 
       def u
-        calculate_u(aa, bb)
+        @u ||= calculate_u
       end
 
       # do not cache this - it's secret and someone might store the
@@ -28,11 +28,20 @@ module SRP
       end
 
       def m1(verifier)
-        calculate_m(aa, bb, secret(verifier))
+        calculate_m(secret(verifier))
       end
 
       def m2(m1, verifier)
-        calculate_m(aa, m1, secret(verifier))
+        sha256_int(@aa, m1, secret(verifier)).hex
+      end
+
+      protected
+      def calculate_u
+        sha256_int(@aa, @bb).hex
+      end
+
+      def calculate_m(s)
+        sha256_int(@aa, @bb, s).hex
       end
 
     end
index de17fb3..94e36af 100644 (file)
@@ -5,23 +5,23 @@ module SRP
 
     include Util
 
-    attr_reader :salt, :verifier
+    attr_reader :salt, :verifier, :username
 
     def initialize(username, password, salt = nil)
       @username = username
       @password = password
       @salt = salt || bigrand(4).hex
-      @multiplier = multiplier # let's cache it
       calculate_verifier
     end
 
     def authenticate(server)
-      a = bigrand(32).hex
-      aa = modpow(GENERATOR, a) # A = g^a (mod N)
-      bb = server.handshake(@username, aa)
-      u = calculate_u(aa, bb)
-      client_s = calculate_client_s(private_key, a, bb, u)
-      server.validate(calculate_m(aa, bb, client_s))
+      @session = SRP::Session.new(self)
+      @session.handshake(server)
+      @session.validate(server)
+    end
+
+    def private_key
+      @private_key ||= calculate_private_key
     end
 
     protected
@@ -30,23 +30,12 @@ module SRP
       @verifier ||= modpow(GENERATOR, private_key)
     end
 
-    def private_key
-      @private_key ||= calculate_private_key
-    end
-
     def calculate_private_key
       shex = '%x' % [@salt]
       inner = sha256_str([@username, @password].join(':'))
       sha256_hex(shex, inner).hex
     end
 
-    def calculate_client_s(x, a, bb, u)
-      base = bb
-      base += BIG_PRIME_N * @multiplier
-      base -= modpow(GENERATOR, x) * @multiplier
-      base = base % BIG_PRIME_N
-      modpow(base, x * u + a)
-    end
   end
 end
 
diff --git a/lib/srp/session.rb b/lib/srp/session.rb
new file mode 100644 (file)
index 0000000..b61058b
--- /dev/null
@@ -0,0 +1,87 @@
+require File.expand_path(File.dirname(__FILE__) + '/util')
+
+module SRP
+  class Session
+    include Util
+    attr_accessor :user, :aa, :bb
+
+    def initialize(user, aa=nil)
+      @user = user
+      aa ? initialize_server(aa) : initialize_client
+    end
+
+    # client -> server: I, A = g^a
+    def handshake(server)
+      @bb = server.handshake(user.username, aa)
+      @u = calculate_u
+    end
+
+    # client -> server: M = H(H(N) xor H(g), H(I), s, A, B, K)
+    def validate(server)
+      server.validate(calculate_m(client_secret))
+    end
+
+    def authenticate!(m)
+      authenticate(m) || raise(SRP::WrongPassword)
+    end
+
+    def authenticate(m)
+      if(m == calculate_m(server_secret))
+        return m2
+      end
+    end
+
+    protected
+
+    def initialize_server(aa)
+      @aa = aa
+      @b = bigrand(32).hex
+      # B = g^b + k v (mod N)
+      @bb = (modpow(GENERATOR, @b) + multiplier * @user.verifier) % BIG_PRIME_N
+      @u = calculate_u
+    end
+
+    def initialize_client
+      @a = bigrand(32).hex
+      @aa = modpow(GENERATOR, @a) # A = g^a (mod N)
+    end
+
+    # client: K = H( (B - kg^x) ^ (a + ux) )
+    def client_secret
+      base = @bb
+      # base += BIG_PRIME_N * @multiplier
+      base -= modpow(GENERATOR, @user.private_key) * multiplier
+      base = base % BIG_PRIME_N
+      modpow(base, @user.private_key * @u + @a)
+    end
+
+    # server: K = H( (Av^u) ^ b )
+    # do not cache this - it's secret and someone might store the
+    # session in a CookieStore
+    def server_secret
+      base = (modpow(@user.verifier, @u) * @aa) % BIG_PRIME_N
+      modpow(base, @b)
+    end
+
+    def m1
+      calculate_m(server_secret)
+    end
+
+    def m2
+      sha256_int(@aa, m1, server_secret).hex
+    end
+
+    # this is outdated - SRP 6a uses
+    # M = H(H(N) xor H(g), H(I), s, A, B, K)
+    def calculate_m(s)
+      sha256_int(@aa, @bb, s).hex
+    end
+
+    def calculate_u
+      sha256_int(@aa, @bb).hex
+    end
+  end
+end
+
+
+
index 087ce5d..50ff9bb 100644 (file)
@@ -61,13 +61,6 @@ d15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e5
       sha256_hex(BIG_PRIME_N.to_s(16), ghex).hex
     end
 
-    def calculate_m(aa, bb, s)
-      sha256_int(aa, bb, s).hex
-    end
-
-    def calculate_u(aa, bb)
-      sha256_int(aa, bb).hex
-    end
   end
 
 end