diff --git a/smack-core/build.gradle b/smack-core/build.gradle index f92a34b447..79719c51f5 100644 --- a/smack-core/build.gradle +++ b/smack-core/build.gradle @@ -10,7 +10,7 @@ dependencies { compile "org.jxmpp:jxmpp-core:$jxmppVersion" compile "org.jxmpp:jxmpp-jid:$jxmppVersion" compile "org.minidns:minidns-core:$miniDnsVersion" - compile "org.bouncycastle:bcprov-jdk15on:1.57" + compile "org.bouncycastle:bcprov-jdk15on:$bouncyCastleVersion" testCompile project(':smack-xmlparser-stax') testCompile project(':smack-xmlparser-xpp3') testCompile "org.jxmpp:jxmpp-jid:$jxmppVersion:tests" diff --git a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanism.java b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanism.java index 902b4ab0fa..34157bf7fd 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanism.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanism.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.math.BigInteger; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.security.auth.callback.CallbackHandler; @@ -26,6 +25,9 @@ import org.jivesoftware.smack.SmackException.SmackSaslException; import org.jivesoftware.smack.sasl.SASLMechanism; +import org.jivesoftware.smack.util.SHA1; +import org.jivesoftware.smack.util.stringencoder.Base32; + import org.bouncycastle.asn1.ASN1ObjectIdentifier; /** @@ -64,37 +66,43 @@ public class GssApiMechanism extends SASLMechanism{ */ public String generateSASLMechanismNameFromGSSApiOIDs (String objectIdentifier) throws NoSuchAlgorithmException, IOException { - /* - * If any padding or non-alphabet characters are encountered, - * the name is not a GS2 family mechanism name. - * This name denotes that the server does not support channel binding, - * because the suffix "-PLUS" is missing . - */ + // To generate a SHA-1 hash string over ASN1.DER. + byte[] ASN1_DER = getASN1DERencoding(objectIdentifier); + String sha1_hash = SHA1.hex(ASN1_DER); - // To calculate the binary SHA-1 Hash - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] messageDigest = md.digest(getASN1DERencoding(objectIdentifier)); - BigInteger no = new BigInteger(1, messageDigest); - String hashtext = no.toString(16); - while (hashtext.length() < 32) { - hashtext = "0" + hashtext; - } - String binarySHA1Hash = getFirst_7_OctetsInBinary(hashtext); - binarySHA1Hash = binarySHA1Hash.substring(0, 54); + // Obtain first 55 bits of the SHA-1 hash. + String binary55Bits = getbinary55Bits(sha1_hash); - String mechanismName = GS2_PREFIX + getBase32Encoding(binarySHA1Hash); + // Make groups of 5 bits each + String[] binaryGroups = new String[11]; + for (int i = 0 ; i < binary55Bits.length() / 5 ; i++) { + String binaryGroup = ""; + for (int j = 0 ; j < 5 ; j++) { + binaryGroup += binary55Bits.charAt(5 * i + j); + } + // int decimalForGroup = Integer.parseInt(binaryGroup,2); - return mechanismName; - } + binaryGroups[i] = binaryGroup; + } - public String getBase32Encoding(String binarySHA1Hash) { - return binarySHA1Hash; + // Base32 encoding for the above binaryGroups + String base32Encoding = ""; + for (int i = 0 ; i < 11 ; i++) { + int decimalValue = Integer.parseInt(binaryGroups[i], 2); + base32Encoding += Base32.encodeIntValue(decimalValue); + } + return GS2_PREFIX + base32Encoding; } - public String getFirst_7_OctetsInBinary(String hashtext) { - // first_7_octets_to_binary_drop_last_bit = "00011100 11111000 11110100 00101011 - // 01011010 10011111 1000000"; - return hashtext; + private static String getbinary55Bits(String sha1_hash) { + // Get first 7 octets. + String first7Octets = sha1_hash.substring(0, 14); + + // Convert first 7 octets of the sha1 hash into binary. + String binaryOctets = new BigInteger(first7Octets, 16).toString(2); + + // Return first 55 bits of the binary hash. + return binaryOctets.substring(0, 55); } public byte[] getASN1DERencoding(String objectIdentifier) throws IOException { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java b/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java index 12856c29ab..8793ea627d 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/stringencoder/Base32.java @@ -45,7 +45,7 @@ public String decode(String string) { } }; - private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ2345678"; + private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; public static StringEncoder getStringEncoder() { return base32Stringencoder; @@ -159,6 +159,10 @@ public static String encode(String str) { return res; } + public static char encodeIntValue(int i) { + return ALPHABET.charAt(i); + } + private static int lenToPadding(int blocklen) { switch (blocklen) { case 1: diff --git a/smack-core/src/test/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanismTest.java b/smack-core/src/test/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanismTest.java index fcf643d9f5..6326cb3d05 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanismTest.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/sasl/gssApi/GssApiMechanismTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.security.NoSuchAlgorithmException; import org.jivesoftware.smack.test.util.SmackTestSuite; @@ -27,14 +28,14 @@ public class GssApiMechanismTest extends SmackTestSuite { public static final String OID = "1.2.840.113554.1.2.2"; - public static final String ASN_1_DER_of_OID_in_HEX = "06092A864886F712010202"; - public static final String SHA1_of_ASN_1_DER_in_HEX = "1c f8 f4 2b 5a 9f 80 fa e9 f8 31 22 6d 5d 9d 56 27 86 61 ad"; - public static final String first_7_octets_to_binary_drop_last_bit = "00011100 11111000 11110100 00101011 01011010 10011111 1000000"; - public static final String binary_in_group_of_5 = "00011 10011 11100 01111 01000 01010 11010 11010 10011 11110 00000"; - public static final String decimal_of_each_group = "3 19 28 15 8 10 26 26 19 30 0"; - public static final String base32Encoding = "DT4PIK22T6A"; + public static final String SHA1_of_ASN_1_DER_in_HEX = "82d27325766bd6c845aa9325516afcff04b04360"; + + public static final String first_7_octets_to_binary_drop_last_bit = "1000001011010010011100110010010101110110011010111101011"; + public static final String binary_in_group_of_5 = "10000 01011 01001 00111 00110 01001 01011 10110 01101 01111 01011"; + public static final String decimal_of_each_group = "16 11 9 7 6 9 11 22 13 15 11"; + public static final String base32Encoding = "QLJHGJLWNPL"; public static final String MECHANISM_NAME = "GS2-" + base32Encoding; @Test @@ -49,4 +50,11 @@ public void generateASN1DERTest() throws IOException { } assertEquals(ASN_1_DER_of_OID_in_HEX, asn1_der_of_oid_in_hex); } + + @Test + public void generateMechanismName() throws IOException, NoSuchAlgorithmException { + GssApiMechanism gssApiMechanism = new GssApiMechanism(); + String mechanismName = gssApiMechanism.generateSASLMechanismNameFromGSSApiOIDs(OID); + assertEquals(MECHANISM_NAME, mechanismName); + } }