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.java221
1 files changed, 106 insertions, 115 deletions
diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java
index abdf6b2..d21ccff 100644
--- a/src/se/leap/leapclient/LeapSRPSession.java
+++ b/src/se/leap/leapclient/LeapSRPSession.java
@@ -4,23 +4,33 @@ import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
import java.util.Arrays;
-import org.jboss.security.Util;
-import org.jboss.security.srp.SRPClientSession;
import org.jboss.security.srp.SRPParameters;
-import org.jboss.security.srp.SRPPermission;
+/**
+ * Implements all SRP algorithm logic.
+ *
+ * It's derived from JBoss implementation, with adjustments to make it work with LEAP platform.
+ *
+ * @author parmegv
+ *
+ */
public class LeapSRPSession {
private SRPParameters params;
+ private String username;
+ private String password;
private BigInteger N;
+ private byte[] N_bytes;
private BigInteger g;
private BigInteger x;
private BigInteger v;
private BigInteger a;
private BigInteger A;
private byte[] K;
+ private SecureRandom pseudoRng;
/** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */
private MessageDigest clientHash;
/** The M2 = H(A | M | K) hash */
@@ -34,7 +44,7 @@ public class LeapSRPSession {
@param password, the user clear text password
@param params, the SRP parameters for the session
*/
- public LeapSRPSession(String username, char[] password, SRPParameters params)
+ public LeapSRPSession(String username, String password, SRPParameters params)
{
this(username, password, params, null);
}
@@ -44,23 +54,24 @@ public class LeapSRPSession {
@param username, the user ID
@param password, the user clear text password
@param params, the SRP parameters for the session
- @param abytes, the random exponent used in the A public key. This must be
- 8 bytes in length.
+ @param abytes, the random exponent used in the A public key
*/
- public LeapSRPSession(String username, char[] password, SRPParameters params,
+ public LeapSRPSession(String username, String password, SRPParameters params,
byte[] abytes) {
- try {
- // Initialize the secure random number and message digests
- Util.init();
- }
- catch(NoSuchAlgorithmException e) {
- }
-
this.params = params;
this.g = new BigInteger(1, params.g);
- byte[] N_bytes = Util.trim(params.N);
+ N_bytes = ConfigHelper.trim(params.N);
this.N = new BigInteger(1, N_bytes);
-
+ this.username = username;
+ this.password = password;
+
+ try {
+ pseudoRng = SecureRandom.getInstance("SHA1PRNG");
+ } catch (NoSuchAlgorithmException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
if( abytes != null ) {
A_LEN = 8*abytes.length;
/* TODO Why did they put this condition?
@@ -70,42 +81,11 @@ public class LeapSRPSession {
*/
this.a = new BigInteger(abytes);
}
-
- // Calculate x = H(s | H(U | ':' | password))
- byte[] salt_bytes = Util.trim(params.s);
- byte[] xb = calculatePasswordHash(username, password, salt_bytes);
- this.x = new BigInteger(1, xb);
-
- // Calculate v = kg^x mod N
- String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0";
- this.v = calculateV(k_string);
- //String v_string = v.toString(16);
+ else
+ A_LEN = 64;
serverHash = newDigest();
clientHash = newDigest();
-
- // H(N)
- byte[] digest_of_n = newDigest().digest(N_bytes);
-
- // H(g)
- byte[] digest_of_g = newDigest().digest(params.g);
-
- // clientHash = H(N) xor H(g)
- byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length);
- //String hxg_string = new BigInteger(1, xor_digest).toString(16);
- clientHash.update(xor_digest);
-
- // clientHash = H(N) xor H(g) | H(U)
- byte[] username_digest = newDigest().digest(Util.trim(username.getBytes()));
- username_digest = Util.trim(username_digest);
- //String username_digest_string = new BigInteger(1, username_digest).toString(16);
- clientHash.update(username_digest);
-
- // clientHash = H(N) xor H(g) | H(U) | s
- //String salt_string = new BigInteger(1, salt_bytes).toString(16);
- clientHash.update(salt_bytes);
-
- K = null;
}
/**
@@ -115,49 +95,38 @@ public class LeapSRPSession {
* @param salt the salt of the user
* @return x
*/
- public byte[] calculatePasswordHash(String username, char[] password, byte[] salt)
+ public byte[] calculatePasswordHash(String username, String password, byte[] salt)
{
+ //password = password.replaceAll("\\\\", "\\\\\\\\");
// Calculate x = H(s | H(U | ':' | password))
MessageDigest x_digest = newDigest();
-
- // Try to convert the username to a byte[] using UTF-8
+ // Try to convert the username to a byte[] using ISO-8859-1
byte[] user = null;
+ byte[] password_bytes = null;
byte[] colon = {};
+ String encoding = "ISO-8859-1";
try {
- user = Util.trim(username.getBytes("UTF-8"));
- colon = Util.trim(":".getBytes("UTF-8"));
+ user = ConfigHelper.trim(username.getBytes(encoding));
+ colon = ConfigHelper.trim(":".getBytes(encoding));
+ password_bytes = ConfigHelper.trim(password.getBytes(encoding));
}
catch(UnsupportedEncodingException e) {
// Use the default platform encoding
- user = Util.trim(username.getBytes());
- colon = Util.trim(":".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;
+ user = ConfigHelper.trim(username.getBytes());
+ colon = ConfigHelper.trim(":".getBytes());
+ password_bytes = ConfigHelper.trim(password.getBytes());
}
-
+
// Build the hash
x_digest.update(user);
x_digest.update(colon);
- x_digest.update(passBytes, 0, passBytesLength);
+ x_digest.update(password_bytes);
byte[] h = x_digest.digest();
- //h = Util.trim(h);
x_digest.reset();
x_digest.update(salt);
x_digest.update(h);
- byte[] x_digest_bytes = Util.trim(x_digest.digest());
+ byte[] x_digest_bytes = x_digest.digest();
return x_digest_bytes;
}
@@ -169,14 +138,22 @@ public class LeapSRPSession {
*/
private BigInteger calculateV(String k_string) {
BigInteger k = new BigInteger(k_string, 16);
- return k.multiply(g.modPow(x, N)); // g^x % N
+ BigInteger v = k.multiply(g.modPow(x, N)); // g^x % N
+ return v;
}
- public byte[] xor(byte[] b1, byte[] b2, int length)
+ /**
+ * Calculates the trimmed xor from two BigInteger numbers
+ * @param b1 the positive source to build first BigInteger
+ * @param b2 the positive source to build second BigInteger
+ * @param length
+ * @return
+ */
+ public byte[] xor(byte[] b1, byte[] b2)
{
//TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa
byte[] xor_digest = new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray();
- return Util.trim(xor_digest);
+ return ConfigHelper.trim(xor_digest);
}
/**
@@ -190,18 +167,11 @@ public class LeapSRPSession {
if( a == null ) {
BigInteger one = BigInteger.ONE;
do {
- a = new BigInteger(A_LEN, Util.getPRNG());
+ a = new BigInteger(A_LEN, pseudoRng);
} while(a.compareTo(one) <= 0);
}
A = g.modPow(a, N);
- Abytes = Util.trim(A.toByteArray());
- //String Abytes_string = new BigInteger(1, Abytes).toString(16);
-
- // clientHash = H(N) xor H(g) | H(U) | A
- clientHash.update(Abytes);
-
- // serverHash = A
- serverHash.update(Abytes);
+ Abytes = ConfigHelper.trim(A.toByteArray());
}
return Abytes;
}
@@ -209,35 +179,68 @@ public class LeapSRPSession {
/**
* Calculates the parameter M1, to be sent to the SRP server.
* It also updates hashes of client and server for further calculations in other methods.
+ * It uses a predefined k.
+ * @param salt_bytes
* @param Bbytes the parameter received from the server, in bytes
* @return the parameter M1
* @throws NoSuchAlgorithmException
*/
- public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException {
+ public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException {
+ // Calculate x = H(s | H(U | ':' | password))
+ byte[] xb = calculatePasswordHash(username, password, ConfigHelper.trim(salt_bytes));
+ this.x = new BigInteger(1, xb);
+
+ // Calculate v = kg^x mod N
+ String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0";
+ this.v = calculateV(k_string);
+
+ // H(N)
+ byte[] digest_of_n = newDigest().digest(N_bytes);
+
+ // H(g)
+ byte[] digest_of_g = newDigest().digest(params.g);
+
+ // clientHash = H(N) xor H(g)
+ byte[] xor_digest = xor(digest_of_n, digest_of_g);
+ clientHash.update(xor_digest);
+
+ // clientHash = H(N) xor H(g) | H(U)
+ byte[] username_digest = newDigest().digest(ConfigHelper.trim(username.getBytes()));
+ username_digest = ConfigHelper.trim(username_digest);
+ clientHash.update(username_digest);
+
+ // clientHash = H(N) xor H(g) | H(U) | s
+ clientHash.update(ConfigHelper.trim(salt_bytes));
+
+ K = null;
+
+ // clientHash = H(N) xor H(g) | H(U) | A
+ byte[] Abytes = ConfigHelper.trim(A.toByteArray());
+ clientHash.update(Abytes);
+
// clientHash = H(N) xor H(g) | H(U) | s | A | B
- Bbytes = Util.trim(Bbytes);
- //String Bbytes_string = new BigInteger(1, Bbytes).toString(16);
+ Bbytes = ConfigHelper.trim(Bbytes);
clientHash.update(Bbytes);
// Calculate S = (B - kg^x) ^ (a + u * x) % N
BigInteger S = calculateS(Bbytes);
- byte[] S_bytes = Util.trim(S.toByteArray());
- //String S_bytes_string = new BigInteger(1, S_bytes).toString(16);
+ byte[] S_bytes = ConfigHelper.trim(S.toByteArray());
// K = SessionHash(S)
String hash_algorithm = params.hashAlgorithm;
MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm);
- K = sessionDigest.digest(S_bytes);
- //K = Util.trim(K);
- //String K_bytes_string = new BigInteger(1, K).toString(16);
+ K = ConfigHelper.trim(sessionDigest.digest(S_bytes));
// clientHash = H(N) xor H(g) | H(U) | A | B | K
clientHash.update(K);
- byte[] M1 = clientHash.digest();
+
+ byte[] M1 = ConfigHelper.trim(clientHash.digest());
// serverHash = Astr + M + K
+ serverHash.update(Abytes);
serverHash.update(M1);
serverHash.update(K);
+
return M1;
}
@@ -247,19 +250,16 @@ public class LeapSRPSession {
* @return the parameter S
*/
private BigInteger calculateS(byte[] Bbytes) {
- byte[] Abytes = Util.trim(A.toByteArray());
+ byte[] Abytes = ConfigHelper.trim(A.toByteArray());
+ Bbytes = ConfigHelper.trim(Bbytes);
byte[] u_bytes = getU(Abytes, Bbytes);
- //ub = Util.trim(ub);
BigInteger B = new BigInteger(1, Bbytes);
BigInteger u = new BigInteger(1, u_bytes);
- //String u_string = u.toString(16);
BigInteger B_minus_v = B.subtract(v);
BigInteger a_ux = a.add(u.multiply(x));
- //String a_ux_string = a_ux.toString(16);
BigInteger S = B_minus_v.modPow(a_ux, N);
-
return S;
}
@@ -271,9 +271,10 @@ public class LeapSRPSession {
*/
public byte[] getU(byte[] Abytes, byte[] Bbytes) {
MessageDigest u_digest = newDigest();
- u_digest.update(Abytes);
- u_digest.update(Bbytes);
- return new BigInteger(1, u_digest.digest()).toByteArray();
+ u_digest.update(ConfigHelper.trim(Abytes));
+ u_digest.update(ConfigHelper.trim(Bbytes));
+ byte[] u_digest_bytes = u_digest.digest();
+ return ConfigHelper.trim(new BigInteger(1, u_digest_bytes).toByteArray());
}
/**
@@ -283,22 +284,12 @@ public class LeapSRPSession {
public boolean verify(byte[] M2)
{
// M2 = H(A | M1 | K)
- byte[] myM2 = serverHash.digest();
+ M2 = ConfigHelper.trim(M2);
+ byte[] myM2 = ConfigHelper.trim(serverHash.digest());
boolean valid = Arrays.equals(M2, myM2);
return valid;
}
- /** Returns the negotiated session K, K = SHA_Interleave(S)
- @return the private session K byte[]
- @throws SecurityException - if the current thread does not have an
- getSessionKey SRPPermission.
- */
- public byte[] getSessionKey() throws SecurityException
- {
- return K;
- }
-
-
/**
* @return a new SHA-256 digest.
*/