diff --git a/README.md b/README.md index 3fa3fc0..458e165 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ JavaSkype requires Java >= 8 to run. You can get this library using Maven by add fr.delthas javaskype - 1.0.7 + 1.0.8 ``` @@ -104,9 +104,6 @@ Run ```maven package```. ## Misceallenous -### Version -1.0.7 - ### Tech JavaSkype uses a very small set of libraries in order to run: @@ -116,7 +113,6 @@ JavaSkype uses a very small set of libraries in order to run: * [JUnit](http://junit.org) - The famous testing library -License ----- +### License MIT diff --git a/pom.xml b/pom.xml index ad3a4cf..0d343b7 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 fr.delthas javaskype - 1.0.7 + 1.0.8 JavaSkype https://github.com/delthas/javaskype diff --git a/src/main/java/fr/delthas/skype/UicConnector.java b/src/main/java/fr/delthas/skype/UicConnector.java index c4670ee..88fbd2d 100644 --- a/src/main/java/fr/delthas/skype/UicConnector.java +++ b/src/main/java/fr/delthas/skype/UicConnector.java @@ -6,6 +6,9 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.math.BigInteger; import java.net.InetAddress; import java.net.NetworkInterface; @@ -22,12 +25,14 @@ import java.security.spec.RSAPublicKeySpec; import java.util.Arrays; import java.util.Base64; +import java.util.Map; import java.util.Random; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +@SuppressWarnings({"unchecked", "rawtypes"}) class UicConnector { private static final Random random = new Random(); @@ -58,6 +63,69 @@ class UicConnector { 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + static { + + // ugly piece of code to bypass Oracle JRE stupid restriction on key lengths + // Skype requires a 256-bit key AES cipher, but Oracle will only allow a key length <= 128-bit due to US export laws + + // the normal ways to fix this are: + // a) to stop using Oracle JRE + // b) to replace two files in the Oracle JRE folder (see http://stackoverflow.com/a/3864276) + // c) to use a simple 128-bit key instead of a 256-bit one + // d) to use an external Cipher implementation (like BouncyCastle) + + // however, none of these ways are practical, or lightweight enough + // so we have to manually override the permissions on key lengths using reflection + + // ugly reflection hack start (we have to override a private static final field from a package-private class...) + + String errorString = "Failed manually overriding key-length permissions. " + + "Please open an issue at https://github.com/Delthas/JavaSkype/issues/ if you see this message. " + + "Try doing this to fix the problem: http://stackoverflow.com/a/3864276"; + + int newMaxKeyLength; + try { + if ((newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES")) < 256) { + Class c = Class.forName("javax.crypto.CryptoAllPermissionCollection"); + Constructor con = c.getDeclaredConstructor(); + con.setAccessible(true); + Object allPermissionCollection = con.newInstance(); + Field f = c.getDeclaredField("all_allowed"); + f.setAccessible(true); + f.setBoolean(allPermissionCollection, true); + + c = Class.forName("javax.crypto.CryptoPermissions"); + con = c.getDeclaredConstructor(); + con.setAccessible(true); + Object allPermissions = con.newInstance(); + f = c.getDeclaredField("perms"); + f.setAccessible(true); + ((Map) f.get(allPermissions)).put("*", allPermissionCollection); + + c = Class.forName("javax.crypto.JceSecurityManager"); + f = c.getDeclaredField("defaultPolicy"); + f.setAccessible(true); + Field mf = Field.class.getDeclaredField("modifiers"); + mf.setAccessible(true); + mf.setInt(f, f.getModifiers() & ~Modifier.FINAL); + // override a final field + // this field won't be optimized out by the compiler because it is set at run-time + f.set(null, allPermissions); + + newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES"); + } + } catch (Exception e) { + throw new RuntimeException(errorString, e); + } + if (newMaxKeyLength < 256) { + // hack failed + throw new RuntimeException(errorString); + } + + // ugly reflection hack end + + } + @SuppressWarnings({"resource", "null"}) public static String getUIC(String username, String password, String nonce) throws IOException, GeneralSecurityException { byte[] sessionKey = new byte[0xC0];