summaryrefslogtreecommitdiff
path: root/src/se/leap/leapclient/LeapSRPSession.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/se/leap/leapclient/LeapSRPSession.java')
-rw-r--r--src/se/leap/leapclient/LeapSRPSession.java126
1 files changed, 93 insertions, 33 deletions
diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java
index 1d1f0c9d..f81e1637 100644
--- a/src/se/leap/leapclient/LeapSRPSession.java
+++ b/src/se/leap/leapclient/LeapSRPSession.java
@@ -1,5 +1,6 @@
package se.leap.leapclient;
+import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -61,33 +62,36 @@ public class LeapSRPSession {
this.params = params;
this.g = new BigInteger(1, params.g);
this.N = new BigInteger(1, params.N);
- if( abytes != null )
- {
+ if( abytes != null ) {
A_LEN = 8*abytes.length;
/* TODO Why did they put this condition?
if( 8*abytes.length != A_LEN )
throw new IllegalArgumentException("The abytes param must be "
+(A_LEN/8)+" in length, abytes.length="+abytes.length);
- */
- this.a = new BigInteger(abytes);
+ */
+ this.a = new BigInteger(abytes);
}
// Calculate x = H(s | H(U | ':' | password))
- byte[] xb = Util.calculatePasswordHash(username, password, params.s);
+ byte[] xb = calculatePasswordHash(username, password, params.s);
this.x = new BigInteger(1, xb);
- this.v = g.modPow(x, N); // g^x % N
- serverHash = Util.newDigest();
- clientHash = Util.newDigest();
+ // Calculate v = kg^x mod N
+ BigInteger k = new BigInteger("bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0", 16);
+ this.v = k.multiply(g.modPow(x, N)); // g^x % N
+
+ serverHash = newDigest();
+ clientHash = newDigest();
+
// H(N)
- byte[] hn = Util.newDigest().digest(params.N);
+ byte[] hn = newDigest().digest(params.N);
// H(g)
- byte[] hg = Util.newDigest().digest(params.g);
+ byte[] hg = newDigest().digest(params.g);
// clientHash = H(N) xor H(g)
- byte[] hxg = Util.xor(hn, hg, 20);
+ byte[] hxg = xor(hn, hg, hg.length);
clientHash.update(hxg);
// clientHash = H(N) xor H(g) | H(U)
- clientHash.update(Util.newDigest().digest(username.getBytes()));
+ clientHash.update(newDigest().digest(username.getBytes()));
// clientHash = H(N) xor H(g) | H(U) | s
clientHash.update(params.s);
K = null;
@@ -96,23 +100,20 @@ public class LeapSRPSession {
/**
* @returns The exponential residue (parameter A) to be sent to the server.
*/
- public byte[] exponential()
- {
+ public byte[] exponential() {
byte[] Abytes = null;
- if(A == null)
- {
+ if(A == null) {
/* If the random component of A has not been specified use a random
number */
- if( a == null )
- {
+ if( a == null ) {
BigInteger one = BigInteger.ONE;
- do
- {
+ do {
a = new BigInteger(A_LEN, Util.getPRNG());
} while(a.compareTo(one) <= 0);
}
A = g.modPow(a, N);
- Abytes = Util.trim(A.toByteArray());
+ //Abytes = Util.trim(A.toByteArray());
+ Abytes = A.toByteArray();
// clientHash = H(N) xor H(g) | H(U) | A
clientHash.update(Abytes);
// serverHash = A
@@ -138,16 +139,9 @@ public class LeapSRPSession {
S = B.subtract(kgx).modPow(aux, N);
K = SHA256(hex2a(S.toString(16)));
*/
- byte[] hA = Util.newDigest().digest(A.toByteArray());
- MessageDigest u_digest = Util.newDigest();
- u_digest.update(A.toByteArray());
- u_digest.update(Bbytes);
- clientHash.update(u_digest.digest());
- byte[] ub = new BigInteger(clientHash.digest()).toByteArray();
- // Calculate S = (B - g^x) ^ (a + u * x) % N
+ byte[] ub = getU(A.toByteArray(), Bbytes);
+ // Calculate S = (B - kg^x) ^ (a + u * x) % N
BigInteger B = new BigInteger(1, Bbytes);
- if( B.compareTo(v) < 0 )
- B = B.add(N);
BigInteger u = new BigInteger(1, ub);
BigInteger B_v = B.subtract(v);
BigInteger a_ux = a.add(u.multiply(x));
@@ -160,9 +154,16 @@ public class LeapSRPSession {
byte[] M1 = clientHash.digest();
return M1;
}
-
-
- /**
+
+
+ public byte[] getU(byte[] Abytes, byte[] Bbytes) {
+ MessageDigest u_digest = Util.newDigest();
+ u_digest.update(Abytes);
+ u_digest.update(Bbytes);
+ return new BigInteger(1, u_digest.digest()).toByteArray();
+ }
+
+ /**
* @param M2 The server's response to the client's challenge
* @returns True if and only if the server's response was correct.
*/
@@ -190,4 +191,63 @@ public class LeapSRPSession {
return K;
}
+ public MessageDigest newDigest()
+ {
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA256");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ return md;
+ }
+
+ public byte[] calculatePasswordHash(String username, char[] password,
+ byte[] salt)
+ {
+ // Calculate x = H(s | H(U | ':' | password))
+ MessageDigest xd = newDigest();
+ // Try to convert the username to a byte[] using UTF-8
+ byte[] user = null;
+ byte[] colon = {};
+ try {
+ user = username.getBytes("UTF-8");
+ colon = ":".getBytes("UTF-8");
+ }
+ catch(UnsupportedEncodingException e) {
+ // Use the default platform encoding
+ user = username.getBytes();
+ colon = ":".getBytes();
+ }
+ byte[] passBytes = new byte[2*password.length];
+ int passBytesLength = 0;
+ for(int p = 0; p < password.length; p ++) {
+ int c = (password[p] & 0x00FFFF);
+ // The low byte of the char
+ byte b0 = (byte) (c & 0x0000FF);
+ // The high byte of the char
+ byte b1 = (byte) ((c & 0x00FF00) >> 8);
+ passBytes[passBytesLength ++] = b0;
+ // Only encode the high byte if c is a multi-byte char
+ if( c > 255 )
+ passBytes[passBytesLength ++] = b1;
+ }
+
+ // Build the hash
+ xd.update(user);
+ xd.update(colon);
+ xd.update(passBytes, 0, passBytesLength);
+ byte[] h = xd.digest();
+ xd.reset();
+ xd.update(salt);
+ xd.update(h);
+ byte[] xb = xd.digest();
+ return xb;
+ }
+
+ public byte[] xor(byte[] b1, byte[] b2, int length)
+ {
+ //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa
+ return new BigInteger(b1).xor(new BigInteger(b2)).toByteArray();
+ }
}