diff options
author | Parménides GV <parmegv@sdf.org> | 2013-04-08 17:12:23 +0200 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2013-04-08 17:12:23 +0200 |
commit | bfee299e998143c801b231060fd5fdb5eb7204b2 (patch) | |
tree | 9aaba6f8c2cfbcb2a459aee1769c78939a440a8e | |
parent | e432ca59a206d05eaa052d09fe22805856d63d14 (diff) |
Xor method fixed. I use BigInteger Java one.
Next step: understand why SHA-256 digest from NG_1024 is not equals to
the one leap_web is calculating.
-rw-r--r-- | src/se/leap/leapclient/ConfigHelper.java | 2 | ||||
-rw-r--r-- | src/se/leap/leapclient/LeapSRPSession.java | 126 |
2 files changed, 94 insertions, 34 deletions
diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index b263c53..5236576 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -36,7 +36,7 @@ public class ConfigHelper { final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; - final public static String NG_1024 = + final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; final public static BigInteger g = BigInteger.valueOf(2); diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 1d1f0c9..f81e163 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(); + } } |