From bfee299e998143c801b231060fd5fdb5eb7204b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 8 Apr 2013 17:12:23 +0200 Subject: 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. --- src/se/leap/leapclient/LeapSRPSession.java | 126 +++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 33 deletions(-) (limited to 'src/se/leap/leapclient/LeapSRPSession.java') 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(); + } } -- cgit v1.2.3